xref: /rk3399_ARM-atf/drivers/ti/pd/ti_psc.c (revision a28114d66a6d43db4accef5fd5d6dab6c059e584)
1*f6db41e0SKamlesh Gurudasani /*
2*f6db41e0SKamlesh Gurudasani  * Copyright (c) 2025-2026 Texas Instruments Incorporated - https://www.ti.com
3*f6db41e0SKamlesh Gurudasani  *
4*f6db41e0SKamlesh Gurudasani  * SPDX-License-Identifier: BSD-3-Clause
5*f6db41e0SKamlesh Gurudasani  */
6*f6db41e0SKamlesh Gurudasani 
7*f6db41e0SKamlesh Gurudasani /*
8*f6db41e0SKamlesh Gurudasani  * Power/Sleep Controller (PSC) Driver
9*f6db41e0SKamlesh Gurudasani  *
10*f6db41e0SKamlesh Gurudasani  * This driver manages the PSC hardware including power domain state transitions,
11*f6db41e0SKamlesh Gurudasani  * LPSC module clock gating, and dependency management between modules and power domains.
12*f6db41e0SKamlesh Gurudasani  */
13*f6db41e0SKamlesh Gurudasani 
14*f6db41e0SKamlesh Gurudasani #include <assert.h>
15*f6db41e0SKamlesh Gurudasani #include <errno.h>
16*f6db41e0SKamlesh Gurudasani #include <stddef.h>
17*f6db41e0SKamlesh Gurudasani 
18*f6db41e0SKamlesh Gurudasani #include <common/debug.h>
19*f6db41e0SKamlesh Gurudasani #include <drivers/delay_timer.h>
20*f6db41e0SKamlesh Gurudasani #include <lib/mmio.h>
21*f6db41e0SKamlesh Gurudasani 
22*f6db41e0SKamlesh Gurudasani #include <ti_clk.h>
23*f6db41e0SKamlesh Gurudasani #include <ti_device.h>
24*f6db41e0SKamlesh Gurudasani #include <ti_device_pm.h>
25*f6db41e0SKamlesh Gurudasani #include <ti_psc.h>
26*f6db41e0SKamlesh Gurudasani 
27*f6db41e0SKamlesh Gurudasani #define PSC_PTCMD		0x120U
28*f6db41e0SKamlesh Gurudasani #define PSC_PTCMD_H		0x124U
29*f6db41e0SKamlesh Gurudasani #define PSC_PTSTAT		0x128U
30*f6db41e0SKamlesh Gurudasani #define PSC_PTSTAT_H		0x12CU
31*f6db41e0SKamlesh Gurudasani #define PSC_PDSTAT_BASE		0x200U
32*f6db41e0SKamlesh Gurudasani #define PSC_PDCTL_BASE		0x300U
33*f6db41e0SKamlesh Gurudasani #define PSC_MDSTAT_BASE		0x800U
34*f6db41e0SKamlesh Gurudasani #define PSC_MDCTL_BASE		0xa00U
35*f6db41e0SKamlesh Gurudasani 
psc_reg(uint32_t base,uint32_t id)36*f6db41e0SKamlesh Gurudasani static inline uint32_t psc_reg(uint32_t base, uint32_t id)
37*f6db41e0SKamlesh Gurudasani {
38*f6db41e0SKamlesh Gurudasani 	return base + (4U * id);
39*f6db41e0SKamlesh Gurudasani }
40*f6db41e0SKamlesh Gurudasani 
41*f6db41e0SKamlesh Gurudasani #define MDSTAT_STATE_MASK		0x3fU
42*f6db41e0SKamlesh Gurudasani #define MDSTAT_BUSY_MASK		0x30U
43*f6db41e0SKamlesh Gurudasani #define MDSTAT_STATE_SWRSTDISABLE	0x00U
44*f6db41e0SKamlesh Gurudasani #define MDSTAT_STATE_SYNCRST		0x01U
45*f6db41e0SKamlesh Gurudasani #define MDSTAT_STATE_DISABLE		0x02U
46*f6db41e0SKamlesh Gurudasani #define MDSTAT_STATE_ENABLE		0x03U
47*f6db41e0SKamlesh Gurudasani 
48*f6db41e0SKamlesh Gurudasani #define MDSTAT_MRSTDONE		BIT(11) /* Module reset done */
49*f6db41e0SKamlesh Gurudasani #define MDSTAT_LRSTDONE		BIT(9)	/* Local reset done */
50*f6db41e0SKamlesh Gurudasani 
51*f6db41e0SKamlesh Gurudasani #define MDCTL_RESET_ISO		BIT(12)		/* Enable reset isolation */
52*f6db41e0SKamlesh Gurudasani #define MDCTL_LRST		BIT(8)		/* Assert local reset when 0 */
53*f6db41e0SKamlesh Gurudasani 
54*f6db41e0SKamlesh Gurudasani #define PDSTAT_STATE_MASK		0x1fU
55*f6db41e0SKamlesh Gurudasani 
56*f6db41e0SKamlesh Gurudasani #define PDCTL_STATE_MASK	BIT(0)
57*f6db41e0SKamlesh Gurudasani #define PDCTL_STATE_OFF		0U
58*f6db41e0SKamlesh Gurudasani #define PDCTL_STATE_ON		1U
59*f6db41e0SKamlesh Gurudasani 
60*f6db41e0SKamlesh Gurudasani /* Timeout values for PSC state transitions */
61*f6db41e0SKamlesh Gurudasani #define PSC_TRANSITION_TIMEOUT_US	10000U	/* 10ms timeout */
62*f6db41e0SKamlesh Gurudasani #define PSC_TRANSITION_DELAY_US		100U	/* 100us delay between checks */
63*f6db41e0SKamlesh Gurudasani #define PSC_TRANSITION_RETRY_COUNT	(PSC_TRANSITION_TIMEOUT_US / PSC_TRANSITION_DELAY_US)
64*f6db41e0SKamlesh Gurudasani 
65*f6db41e0SKamlesh Gurudasani /* Module state return values */
66*f6db41e0SKamlesh Gurudasani #define TI_LPSC_STATE_DISABLED		0U	/* Module is disabled */
67*f6db41e0SKamlesh Gurudasani #define TI_LPSC_STATE_ENABLED		1U	/* Module is enabled or in retention */
68*f6db41e0SKamlesh Gurudasani #define TI_LPSC_STATE_TRANSITIONING	2U	/* Module is transitioning */
69*f6db41e0SKamlesh Gurudasani 
70*f6db41e0SKamlesh Gurudasani static struct ti_device *psc_devs;
71*f6db41e0SKamlesh Gurudasani 
72*f6db41e0SKamlesh Gurudasani static void lpsc_module_get_internal(struct ti_device *dev,
73*f6db41e0SKamlesh Gurudasani 				     struct ti_lpsc_module *module,
74*f6db41e0SKamlesh Gurudasani 				     bool use, bool ret);
75*f6db41e0SKamlesh Gurudasani static void lpsc_module_put_internal(struct ti_device *dev,
76*f6db41e0SKamlesh Gurudasani 				     struct ti_lpsc_module *module,
77*f6db41e0SKamlesh Gurudasani 				     bool use, bool ret);
78*f6db41e0SKamlesh Gurudasani 
psc_read(struct ti_device * dev,uint32_t reg)79*f6db41e0SKamlesh Gurudasani static uint32_t psc_read(struct ti_device *dev, uint32_t reg)
80*f6db41e0SKamlesh Gurudasani {
81*f6db41e0SKamlesh Gurudasani 	const struct ti_psc_drv_data *psc = ti_to_psc_drv_data(ti_get_drv_data(dev));
82*f6db41e0SKamlesh Gurudasani 
83*f6db41e0SKamlesh Gurudasani 	if (psc->base == 0U)
84*f6db41e0SKamlesh Gurudasani 		return 0U;
85*f6db41e0SKamlesh Gurudasani 
86*f6db41e0SKamlesh Gurudasani 	return mmio_read_32(psc->base + reg);
87*f6db41e0SKamlesh Gurudasani }
88*f6db41e0SKamlesh Gurudasani 
psc_write(struct ti_device * dev,uint32_t val,uint32_t reg)89*f6db41e0SKamlesh Gurudasani static void psc_write(struct ti_device *dev, uint32_t val, uint32_t reg)
90*f6db41e0SKamlesh Gurudasani {
91*f6db41e0SKamlesh Gurudasani 	const struct ti_psc_drv_data *psc = ti_to_psc_drv_data(ti_get_drv_data(dev));
92*f6db41e0SKamlesh Gurudasani 
93*f6db41e0SKamlesh Gurudasani 	if (psc->base == 0U)
94*f6db41e0SKamlesh Gurudasani 		return;
95*f6db41e0SKamlesh Gurudasani 
96*f6db41e0SKamlesh Gurudasani 	mmio_write_32(psc->base + reg, val);
97*f6db41e0SKamlesh Gurudasani }
98*f6db41e0SKamlesh Gurudasani 
ti_psc_pd_idx(struct ti_device * dev,const struct ti_psc_pd * pd)99*f6db41e0SKamlesh Gurudasani ti_pd_idx_t ti_psc_pd_idx(struct ti_device *dev, const struct ti_psc_pd *pd)
100*f6db41e0SKamlesh Gurudasani {
101*f6db41e0SKamlesh Gurudasani 	const struct ti_psc_drv_data *psc = ti_to_psc_drv_data(ti_get_drv_data(dev));
102*f6db41e0SKamlesh Gurudasani 	ptrdiff_t diff = pd - psc->powerdomains;
103*f6db41e0SKamlesh Gurudasani 
104*f6db41e0SKamlesh Gurudasani 	return (ti_pd_idx_t) diff;
105*f6db41e0SKamlesh Gurudasani }
106*f6db41e0SKamlesh Gurudasani 
psc_idx2pd(const struct ti_psc_drv_data * psc,ti_pd_idx_t id)107*f6db41e0SKamlesh Gurudasani static inline struct ti_psc_pd *psc_idx2pd(const struct ti_psc_drv_data *psc,
108*f6db41e0SKamlesh Gurudasani 					   ti_pd_idx_t id)
109*f6db41e0SKamlesh Gurudasani {
110*f6db41e0SKamlesh Gurudasani 	return &psc->powerdomains[id];
111*f6db41e0SKamlesh Gurudasani }
112*f6db41e0SKamlesh Gurudasani 
get_psc_pd_data(struct ti_device * dev,struct ti_psc_pd * pd)113*f6db41e0SKamlesh Gurudasani static const struct ti_psc_pd_data *get_psc_pd_data(struct ti_device *dev,
114*f6db41e0SKamlesh Gurudasani 						    struct ti_psc_pd *pd)
115*f6db41e0SKamlesh Gurudasani {
116*f6db41e0SKamlesh Gurudasani 	const struct ti_psc_drv_data *psc = ti_to_psc_drv_data(ti_get_drv_data(dev));
117*f6db41e0SKamlesh Gurudasani 
118*f6db41e0SKamlesh Gurudasani 	return &psc->pd_data[ti_psc_pd_idx(dev, pd)];
119*f6db41e0SKamlesh Gurudasani }
120*f6db41e0SKamlesh Gurudasani 
ti_lpsc_module_idx(struct ti_device * dev,const struct ti_lpsc_module * module)121*f6db41e0SKamlesh Gurudasani ti_lpsc_idx_t ti_lpsc_module_idx(struct ti_device *dev, const struct ti_lpsc_module *module)
122*f6db41e0SKamlesh Gurudasani {
123*f6db41e0SKamlesh Gurudasani 	const struct ti_psc_drv_data *psc = ti_to_psc_drv_data(ti_get_drv_data(dev));
124*f6db41e0SKamlesh Gurudasani 	ptrdiff_t diff = module - psc->modules;
125*f6db41e0SKamlesh Gurudasani 
126*f6db41e0SKamlesh Gurudasani 	return (ti_lpsc_idx_t) diff;
127*f6db41e0SKamlesh Gurudasani }
128*f6db41e0SKamlesh Gurudasani 
psc_idx2mod(const struct ti_psc_drv_data * psc,ti_lpsc_idx_t id)129*f6db41e0SKamlesh Gurudasani static inline struct ti_lpsc_module *psc_idx2mod(const struct ti_psc_drv_data *psc,
130*f6db41e0SKamlesh Gurudasani 						 ti_lpsc_idx_t id)
131*f6db41e0SKamlesh Gurudasani {
132*f6db41e0SKamlesh Gurudasani 	return &psc->modules[id];
133*f6db41e0SKamlesh Gurudasani }
134*f6db41e0SKamlesh Gurudasani 
ti_psc_pd_wait(struct ti_device * dev,struct ti_psc_pd * pd)135*f6db41e0SKamlesh Gurudasani void ti_psc_pd_wait(struct ti_device *dev, struct ti_psc_pd *pd)
136*f6db41e0SKamlesh Gurudasani {
137*f6db41e0SKamlesh Gurudasani 	uint32_t psc_ptstat = PSC_PTSTAT;
138*f6db41e0SKamlesh Gurudasani 	ti_pd_idx_t psc_idx    = ti_psc_pd_idx(dev, pd);
139*f6db41e0SKamlesh Gurudasani 
140*f6db41e0SKamlesh Gurudasani 	if (0U == (get_psc_pd_data(dev, pd)->flags & TI_PSC_PD_ALWAYSON)) {
141*f6db41e0SKamlesh Gurudasani 		uint32_t retry_count = PSC_TRANSITION_RETRY_COUNT;
142*f6db41e0SKamlesh Gurudasani 		/* power domain >= 32 uses PSC_PTSTAT_H register */
143*f6db41e0SKamlesh Gurudasani 		if (psc_idx >= 32U) {
144*f6db41e0SKamlesh Gurudasani 			psc_ptstat = PSC_PTSTAT_H;
145*f6db41e0SKamlesh Gurudasani 		}
146*f6db41e0SKamlesh Gurudasani 		while ((((psc_read(dev, psc_ptstat)) &
147*f6db41e0SKamlesh Gurudasani 			 BIT(psc_idx % 32U)) != 0U) && (retry_count > 0U)) {
148*f6db41e0SKamlesh Gurudasani 			udelay(PSC_TRANSITION_DELAY_US);
149*f6db41e0SKamlesh Gurudasani 			retry_count--;
150*f6db41e0SKamlesh Gurudasani 		}
151*f6db41e0SKamlesh Gurudasani 		if (retry_count == 0U) {
152*f6db41e0SKamlesh Gurudasani 			/* Directly convert to psc to get psc_idx */
153*f6db41e0SKamlesh Gurudasani 			VERBOSE("PSC transition timeout: psc_id=%d pd_id=%d\n",
154*f6db41e0SKamlesh Gurudasani 				(ti_to_psc_drv_data(ti_get_drv_data(dev)))->psc_idx,
155*f6db41e0SKamlesh Gurudasani 				ti_psc_pd_idx(dev, pd));
156*f6db41e0SKamlesh Gurudasani 		}
157*f6db41e0SKamlesh Gurudasani 	}
158*f6db41e0SKamlesh Gurudasani }
159*f6db41e0SKamlesh Gurudasani 
pd_initiate(struct ti_device * dev,struct ti_psc_pd * pd)160*f6db41e0SKamlesh Gurudasani static void pd_initiate(struct ti_device *dev, struct ti_psc_pd *pd)
161*f6db41e0SKamlesh Gurudasani {
162*f6db41e0SKamlesh Gurudasani 	uint32_t psc_ptcmd = PSC_PTCMD;
163*f6db41e0SKamlesh Gurudasani 	ti_pd_idx_t psc_idx   = ti_psc_pd_idx(dev, pd);
164*f6db41e0SKamlesh Gurudasani 
165*f6db41e0SKamlesh Gurudasani 	/* power domain >= 32 uses PSC_PTCMD_H register */
166*f6db41e0SKamlesh Gurudasani 	if (psc_idx >= 32U) {
167*f6db41e0SKamlesh Gurudasani 		psc_ptcmd = PSC_PTCMD_H;
168*f6db41e0SKamlesh Gurudasani 	}
169*f6db41e0SKamlesh Gurudasani 
170*f6db41e0SKamlesh Gurudasani 	/* Note: This is a state machine reg */
171*f6db41e0SKamlesh Gurudasani 	psc_write(dev, (uint32_t) BIT(psc_idx % 32U), psc_ptcmd);
172*f6db41e0SKamlesh Gurudasani }
173*f6db41e0SKamlesh Gurudasani 
174*f6db41e0SKamlesh Gurudasani /**
175*f6db41e0SKamlesh Gurudasani  * psc_pd_clk_get() - Enable clocks necessary for power domain
176*f6db41e0SKamlesh Gurudasani  * @data: The const data for the power domain
177*f6db41e0SKamlesh Gurudasani  *
178*f6db41e0SKamlesh Gurudasani  * This function calls ti_clk_get on each of the clocks listed
179*f6db41e0SKamlesh Gurudasani  * under clock_dep for a given power domain. Some power domains
180*f6db41e0SKamlesh Gurudasani  * require certain clocks to be running while the power domain
181*f6db41e0SKamlesh Gurudasani  * is in transition or on.
182*f6db41e0SKamlesh Gurudasani  */
psc_pd_clk_get(const struct ti_psc_pd_data * data)183*f6db41e0SKamlesh Gurudasani static void psc_pd_clk_get(const struct ti_psc_pd_data *data)
184*f6db41e0SKamlesh Gurudasani {
185*f6db41e0SKamlesh Gurudasani 	uint32_t i;
186*f6db41e0SKamlesh Gurudasani 
187*f6db41e0SKamlesh Gurudasani 	for (i = 0U; i < ARRAY_SIZE(data->clock_dep); i++) {
188*f6db41e0SKamlesh Gurudasani 		struct ti_clk *clkp = ti_clk_lookup(data->clock_dep[i]);
189*f6db41e0SKamlesh Gurudasani 
190*f6db41e0SKamlesh Gurudasani 		if (clkp != NULL) {
191*f6db41e0SKamlesh Gurudasani 			(void) ti_clk_get(clkp);
192*f6db41e0SKamlesh Gurudasani 		}
193*f6db41e0SKamlesh Gurudasani 	}
194*f6db41e0SKamlesh Gurudasani }
195*f6db41e0SKamlesh Gurudasani 
ti_psc_pd_get(struct ti_device * dev,struct ti_psc_pd * pd)196*f6db41e0SKamlesh Gurudasani void ti_psc_pd_get(struct ti_device *dev, struct ti_psc_pd *pd)
197*f6db41e0SKamlesh Gurudasani {
198*f6db41e0SKamlesh Gurudasani 	const struct ti_psc_drv_data *psc = ti_to_psc_drv_data(ti_get_drv_data(dev));
199*f6db41e0SKamlesh Gurudasani 	uint32_t idx = ti_psc_pd_idx(dev, pd);
200*f6db41e0SKamlesh Gurudasani 	uint32_t pdctl;
201*f6db41e0SKamlesh Gurudasani 
202*f6db41e0SKamlesh Gurudasani 	VERBOSE("PD_GET: psc_id=%d pd_id=%d use_count=%d\n",
203*f6db41e0SKamlesh Gurudasani 		psc->psc_idx, idx, pd->use_count);
204*f6db41e0SKamlesh Gurudasani 
205*f6db41e0SKamlesh Gurudasani 	if ((pd->use_count++) != 0U) {
206*f6db41e0SKamlesh Gurudasani 		return;
207*f6db41e0SKamlesh Gurudasani 	}
208*f6db41e0SKamlesh Gurudasani 
209*f6db41e0SKamlesh Gurudasani 	if ((psc->pd_data[idx].flags & TI_PSC_PD_ALWAYSON) != 0U) {
210*f6db41e0SKamlesh Gurudasani 		return;
211*f6db41e0SKamlesh Gurudasani 	}
212*f6db41e0SKamlesh Gurudasani 
213*f6db41e0SKamlesh Gurudasani 	/* Verify any previous transitions have completed */
214*f6db41e0SKamlesh Gurudasani 	ti_psc_pd_wait(dev, pd);
215*f6db41e0SKamlesh Gurudasani 
216*f6db41e0SKamlesh Gurudasani 	if ((psc->pd_data[idx].flags & TI_PSC_PD_DEPENDS) != 0U) {
217*f6db41e0SKamlesh Gurudasani 		ti_psc_pd_get(dev, psc_idx2pd(psc,
218*f6db41e0SKamlesh Gurudasani 					      (ti_pd_idx_t) psc->pd_data[idx].depends));
219*f6db41e0SKamlesh Gurudasani 	}
220*f6db41e0SKamlesh Gurudasani 
221*f6db41e0SKamlesh Gurudasani 	psc_pd_clk_get(&psc->pd_data[idx]);
222*f6db41e0SKamlesh Gurudasani 
223*f6db41e0SKamlesh Gurudasani 	pdctl = psc_read(dev, psc_reg(PSC_PDCTL_BASE, idx));
224*f6db41e0SKamlesh Gurudasani 
225*f6db41e0SKamlesh Gurudasani 	if ((pdctl & PDCTL_STATE_MASK) != PDCTL_STATE_ON) {
226*f6db41e0SKamlesh Gurudasani 		/* Avoid redundant power-up transitions */
227*f6db41e0SKamlesh Gurudasani 		pdctl &= ~PDCTL_STATE_MASK;
228*f6db41e0SKamlesh Gurudasani 		pdctl |= PDCTL_STATE_ON;
229*f6db41e0SKamlesh Gurudasani 
230*f6db41e0SKamlesh Gurudasani 		/* Note: This is a state machine reg */
231*f6db41e0SKamlesh Gurudasani 		psc_write(dev, pdctl, psc_reg(PSC_PDCTL_BASE, idx));
232*f6db41e0SKamlesh Gurudasani 
233*f6db41e0SKamlesh Gurudasani 		pd_initiate(dev, pd);
234*f6db41e0SKamlesh Gurudasani 		ti_psc_pd_wait(dev, pd);
235*f6db41e0SKamlesh Gurudasani 	}
236*f6db41e0SKamlesh Gurudasani 
237*f6db41e0SKamlesh Gurudasani 	psc->data->pds_enabled |= (uint32_t) BIT(idx);
238*f6db41e0SKamlesh Gurudasani }
239*f6db41e0SKamlesh Gurudasani 
240*f6db41e0SKamlesh Gurudasani /**
241*f6db41e0SKamlesh Gurudasani  * psc_pd_clk_put() - Disable clocks necessary for power domain
242*f6db41e0SKamlesh Gurudasani  * @data: The const data for the power domain
243*f6db41e0SKamlesh Gurudasani  *
244*f6db41e0SKamlesh Gurudasani  * This function calls ti_clk_put on each of the clocks listed
245*f6db41e0SKamlesh Gurudasani  * under clock_dep for a given power domain. Some power domains
246*f6db41e0SKamlesh Gurudasani  * require certain clocks to be running while the power domain
247*f6db41e0SKamlesh Gurudasani  * is in transition or on.
248*f6db41e0SKamlesh Gurudasani  */
psc_pd_clk_put(const struct ti_psc_pd_data * data)249*f6db41e0SKamlesh Gurudasani static void psc_pd_clk_put(const struct ti_psc_pd_data *data)
250*f6db41e0SKamlesh Gurudasani {
251*f6db41e0SKamlesh Gurudasani 	uint32_t i;
252*f6db41e0SKamlesh Gurudasani 
253*f6db41e0SKamlesh Gurudasani 	for (i = 0U; i < ARRAY_SIZE(data->clock_dep); i++) {
254*f6db41e0SKamlesh Gurudasani 		struct ti_clk *clkp = ti_clk_lookup(data->clock_dep[i]);
255*f6db41e0SKamlesh Gurudasani 
256*f6db41e0SKamlesh Gurudasani 		if (clkp != NULL) {
257*f6db41e0SKamlesh Gurudasani 			ti_clk_put(clkp);
258*f6db41e0SKamlesh Gurudasani 		}
259*f6db41e0SKamlesh Gurudasani 	}
260*f6db41e0SKamlesh Gurudasani }
261*f6db41e0SKamlesh Gurudasani 
ti_psc_pd_put(struct ti_device * dev,struct ti_psc_pd * pd)262*f6db41e0SKamlesh Gurudasani void ti_psc_pd_put(struct ti_device *dev, struct ti_psc_pd *pd)
263*f6db41e0SKamlesh Gurudasani {
264*f6db41e0SKamlesh Gurudasani 	uint32_t pdctl;
265*f6db41e0SKamlesh Gurudasani 	const struct ti_psc_drv_data *psc = ti_to_psc_drv_data(ti_get_drv_data(dev));
266*f6db41e0SKamlesh Gurudasani 	uint32_t idx = ti_psc_pd_idx(dev, pd);
267*f6db41e0SKamlesh Gurudasani 
268*f6db41e0SKamlesh Gurudasani 	VERBOSE("PD_PUT: psc_id=%d pd_id=%d use_count=%d\n",
269*f6db41e0SKamlesh Gurudasani 		psc->psc_idx, idx, pd->use_count);
270*f6db41e0SKamlesh Gurudasani 
271*f6db41e0SKamlesh Gurudasani 	if ((--pd->use_count) != 0U) {
272*f6db41e0SKamlesh Gurudasani 		return;
273*f6db41e0SKamlesh Gurudasani 	}
274*f6db41e0SKamlesh Gurudasani 
275*f6db41e0SKamlesh Gurudasani 	if ((psc->pd_data[idx].flags & TI_PSC_PD_ALWAYSON) != 0U) {
276*f6db41e0SKamlesh Gurudasani 		return;
277*f6db41e0SKamlesh Gurudasani 	}
278*f6db41e0SKamlesh Gurudasani 
279*f6db41e0SKamlesh Gurudasani 	/* Verify any previous transitions have completed */
280*f6db41e0SKamlesh Gurudasani 	ti_psc_pd_wait(dev, pd);
281*f6db41e0SKamlesh Gurudasani 
282*f6db41e0SKamlesh Gurudasani 	pdctl = psc_read(dev, psc_reg(PSC_PDCTL_BASE, idx));
283*f6db41e0SKamlesh Gurudasani 	if ((pdctl & PDCTL_STATE_MASK) != PDCTL_STATE_OFF) {
284*f6db41e0SKamlesh Gurudasani 		/* Avoid redundant power-up transitions */
285*f6db41e0SKamlesh Gurudasani 		pdctl &= ~PDCTL_STATE_MASK;
286*f6db41e0SKamlesh Gurudasani 		pdctl |= PDCTL_STATE_OFF;
287*f6db41e0SKamlesh Gurudasani 		/* Note: This is a state machine reg */
288*f6db41e0SKamlesh Gurudasani 		psc_write(dev, pdctl, psc_reg(PSC_PDCTL_BASE, idx));
289*f6db41e0SKamlesh Gurudasani 
290*f6db41e0SKamlesh Gurudasani 		pd_initiate(dev, pd);
291*f6db41e0SKamlesh Gurudasani 		ti_psc_pd_wait(dev, pd);
292*f6db41e0SKamlesh Gurudasani 	}
293*f6db41e0SKamlesh Gurudasani 
294*f6db41e0SKamlesh Gurudasani 	psc_pd_clk_put(&psc->pd_data[idx]);
295*f6db41e0SKamlesh Gurudasani 
296*f6db41e0SKamlesh Gurudasani 	if ((psc->pd_data[idx].flags & TI_PSC_PD_DEPENDS) != 0U) {
297*f6db41e0SKamlesh Gurudasani 		ti_psc_pd_put(dev, psc_idx2pd(psc,
298*f6db41e0SKamlesh Gurudasani 					      (ti_pd_idx_t) psc->pd_data[idx].depends));
299*f6db41e0SKamlesh Gurudasani 	}
300*f6db41e0SKamlesh Gurudasani 
301*f6db41e0SKamlesh Gurudasani 	psc->data->pds_enabled &= ~((uint32_t) BIT(idx));
302*f6db41e0SKamlesh Gurudasani }
303*f6db41e0SKamlesh Gurudasani 
304*f6db41e0SKamlesh Gurudasani /**
305*f6db41e0SKamlesh Gurudasani  * lpsc_module_sync_state() - Sync the hardware state of a module with it's software state.
306*f6db41e0SKamlesh Gurudasani  * @dev: The device struct for this PSC.
307*f6db41e0SKamlesh Gurudasani  * @module: The module data for this module.
308*f6db41e0SKamlesh Gurudasani  * @domain_reset: True if syncing just prior to a domain reset,
309*f6db41e0SKamlesh Gurudasani  *                in which case actual transitions are avoided.
310*f6db41e0SKamlesh Gurudasani  *
311*f6db41e0SKamlesh Gurudasani  * This function examines the current state of a given LPSC module and
312*f6db41e0SKamlesh Gurudasani  * compares it with the last programmed state. If there have been changes it
313*f6db41e0SKamlesh Gurudasani  * programs the hardware appropriately. It also enables/disables any
314*f6db41e0SKamlesh Gurudasani  * dependencies as necessary.
315*f6db41e0SKamlesh Gurudasani  */
lpsc_module_sync_state(struct ti_device * dev,struct ti_lpsc_module * module,bool domain_reset)316*f6db41e0SKamlesh Gurudasani static void lpsc_module_sync_state(struct ti_device *dev, struct ti_lpsc_module *module,
317*f6db41e0SKamlesh Gurudasani 				   bool domain_reset)
318*f6db41e0SKamlesh Gurudasani {
319*f6db41e0SKamlesh Gurudasani 	const struct ti_psc_drv_data *psc = ti_to_psc_drv_data(ti_get_drv_data(dev));
320*f6db41e0SKamlesh Gurudasani 	uint32_t mdctl;
321*f6db41e0SKamlesh Gurudasani 	uint32_t idx = ti_lpsc_module_idx(dev, module);
322*f6db41e0SKamlesh Gurudasani 	const struct ti_lpsc_module_data *data = &psc->mod_data[idx];
323*f6db41e0SKamlesh Gurudasani 	struct ti_psc_pd *pd = psc_idx2pd(psc, (ti_pd_idx_t) data->powerdomain);
324*f6db41e0SKamlesh Gurudasani 	uint8_t state;		     /* Target module state */
325*f6db41e0SKamlesh Gurudasani 	uint8_t old_state;	     /* Original module state */
326*f6db41e0SKamlesh Gurudasani 	bool new_mrst_ret;     /* MRST induced retention */
327*f6db41e0SKamlesh Gurudasani 	bool old_msrt_ret;
328*f6db41e0SKamlesh Gurudasani 	bool old_pwr;	       /* Power domain should be enabled */
329*f6db41e0SKamlesh Gurudasani 	bool old_ret;	       /* Retention of any kind */
330*f6db41e0SKamlesh Gurudasani 	bool old_en;	       /* Enabled (clocks running) */
331*f6db41e0SKamlesh Gurudasani 	bool old_rst;
332*f6db41e0SKamlesh Gurudasani 	bool new_pwr;
333*f6db41e0SKamlesh Gurudasani 	bool new_ret;
334*f6db41e0SKamlesh Gurudasani 	bool new_en;
335*f6db41e0SKamlesh Gurudasani 	bool new_rst;
336*f6db41e0SKamlesh Gurudasani 	bool transition;       /* A state transition is necessary */
337*f6db41e0SKamlesh Gurudasani 	bool get_en;	       /* Moving from disabled to enabled */
338*f6db41e0SKamlesh Gurudasani 	bool get_ret;	       /* Moving from off to retention */
339*f6db41e0SKamlesh Gurudasani 	bool get_pwr;	       /* Moving from power domain off to on */
340*f6db41e0SKamlesh Gurudasani 	bool put_en;	       /* Moving from enabled to disabled */
341*f6db41e0SKamlesh Gurudasani 	bool put_ret;	       /* Moving from retention to off */
342*f6db41e0SKamlesh Gurudasani 	bool put_pwr;	       /* Moving from power domain on to off */
343*f6db41e0SKamlesh Gurudasani 
344*f6db41e0SKamlesh Gurudasani 	/*
345*f6db41e0SKamlesh Gurudasani 	 * Determine target state based on usage counts and module reset:
346*f6db41e0SKamlesh Gurudasani 	 *
347*f6db41e0SKamlesh Gurudasani 	 * +---------+-----------+-------+-------------------------------+
348*f6db41e0SKamlesh Gurudasani 	 * + Enabled | Retention | Reset | State			 |
349*f6db41e0SKamlesh Gurudasani 	 * +=========+===========+=======+===============================+
350*f6db41e0SKamlesh Gurudasani 	 * | No	     | No	 | NA	 | SwRstDisabled (may power off) |
351*f6db41e0SKamlesh Gurudasani 	 * +---------+-----------+-------+-------------------------------+
352*f6db41e0SKamlesh Gurudasani 	 * | No	     | Yes	 | No	 | Disabled			 |
353*f6db41e0SKamlesh Gurudasani 	 * +---------+-----------+-------+-------------------------------+
354*f6db41e0SKamlesh Gurudasani 	 * | No	     | Yes	 | Yes	 | SwRstDisabled (powered-on)	 |
355*f6db41e0SKamlesh Gurudasani 	 * +---------+-----------+-------+-------------------------------+
356*f6db41e0SKamlesh Gurudasani 	 * | Yes     | NA	 | No	 | Enabled			 |
357*f6db41e0SKamlesh Gurudasani 	 * +---------+-----------+-------+-------------------------------+
358*f6db41e0SKamlesh Gurudasani 	 * | Yes     | NA	 | Yes	 | SyncReset			 |
359*f6db41e0SKamlesh Gurudasani 	 * +---------+-----------+-------+-------------------------------+
360*f6db41e0SKamlesh Gurudasani 	 */
361*f6db41e0SKamlesh Gurudasani 	new_mrst_ret = false;
362*f6db41e0SKamlesh Gurudasani 	if ((module->use_count == 0U) && (module->ret_count == 0U)) {
363*f6db41e0SKamlesh Gurudasani 		state = MDSTAT_STATE_SWRSTDISABLE;
364*f6db41e0SKamlesh Gurudasani 	} else if (module->use_count == 0U) {
365*f6db41e0SKamlesh Gurudasani 		/* Retention enabled, but module disabled */
366*f6db41e0SKamlesh Gurudasani 		if (module->mrst_active == 0U) {
367*f6db41e0SKamlesh Gurudasani 			state = MDSTAT_STATE_DISABLE;
368*f6db41e0SKamlesh Gurudasani 		} else {
369*f6db41e0SKamlesh Gurudasani 			new_mrst_ret = true;
370*f6db41e0SKamlesh Gurudasani 			state = MDSTAT_STATE_SWRSTDISABLE;
371*f6db41e0SKamlesh Gurudasani 		}
372*f6db41e0SKamlesh Gurudasani 	} else {
373*f6db41e0SKamlesh Gurudasani 		/* Module enabled (retention setting is don't care) */
374*f6db41e0SKamlesh Gurudasani 		if (module->mrst_active == 0U) {
375*f6db41e0SKamlesh Gurudasani 			state = MDSTAT_STATE_ENABLE;
376*f6db41e0SKamlesh Gurudasani 		} else {
377*f6db41e0SKamlesh Gurudasani 			state = MDSTAT_STATE_SYNCRST;
378*f6db41e0SKamlesh Gurudasani 		}
379*f6db41e0SKamlesh Gurudasani 	}
380*f6db41e0SKamlesh Gurudasani 
381*f6db41e0SKamlesh Gurudasani 	/* Promote target state based on disallowed states */
382*f6db41e0SKamlesh Gurudasani 	if ((state == MDSTAT_STATE_SWRSTDISABLE) &&
383*f6db41e0SKamlesh Gurudasani 	    ((data->flags & TI_LPSC_NO_MODULE_RESET) != 0U)) {
384*f6db41e0SKamlesh Gurudasani 		state = MDSTAT_STATE_DISABLE;
385*f6db41e0SKamlesh Gurudasani 		new_mrst_ret = false;
386*f6db41e0SKamlesh Gurudasani 	}
387*f6db41e0SKamlesh Gurudasani 	if ((state == MDSTAT_STATE_DISABLE) && ((data->flags & TI_LPSC_NO_CLOCK_GATING) != 0U)) {
388*f6db41e0SKamlesh Gurudasani 		state = MDSTAT_STATE_ENABLE;
389*f6db41e0SKamlesh Gurudasani 	}
390*f6db41e0SKamlesh Gurudasani 	if ((state == MDSTAT_STATE_SYNCRST) && ((data->flags & TI_LPSC_NO_MODULE_RESET) != 0U)) {
391*f6db41e0SKamlesh Gurudasani 		state = MDSTAT_STATE_ENABLE;
392*f6db41e0SKamlesh Gurudasani 	}
393*f6db41e0SKamlesh Gurudasani 
394*f6db41e0SKamlesh Gurudasani 	/* Track transition of old state to new state */
395*f6db41e0SKamlesh Gurudasani 	old_state = module->sw_state;
396*f6db41e0SKamlesh Gurudasani 	module->sw_state = state;
397*f6db41e0SKamlesh Gurudasani 	old_msrt_ret = module->sw_mrst_ret;
398*f6db41e0SKamlesh Gurudasani 	module->sw_mrst_ret =  new_mrst_ret;
399*f6db41e0SKamlesh Gurudasani 
400*f6db41e0SKamlesh Gurudasani 	/* Previous setting of retention, enable, and reset */
401*f6db41e0SKamlesh Gurudasani 	old_ret = old_state != MDSTAT_STATE_SWRSTDISABLE;
402*f6db41e0SKamlesh Gurudasani 	old_pwr = old_ret || old_msrt_ret;
403*f6db41e0SKamlesh Gurudasani 	old_en = (old_state == MDSTAT_STATE_SYNCRST) || (old_state == MDSTAT_STATE_ENABLE);
404*f6db41e0SKamlesh Gurudasani 	old_rst = (old_state != MDSTAT_STATE_ENABLE) && (old_state != MDSTAT_STATE_DISABLE);
405*f6db41e0SKamlesh Gurudasani 
406*f6db41e0SKamlesh Gurudasani 	/* New setting of retention, enable, and reset */
407*f6db41e0SKamlesh Gurudasani 	new_ret = state != MDSTAT_STATE_SWRSTDISABLE;
408*f6db41e0SKamlesh Gurudasani 	new_pwr = new_ret || new_mrst_ret;
409*f6db41e0SKamlesh Gurudasani 	new_en = (state == MDSTAT_STATE_SYNCRST) || (state == MDSTAT_STATE_ENABLE);
410*f6db41e0SKamlesh Gurudasani 	new_rst = (state != MDSTAT_STATE_ENABLE) && (state != MDSTAT_STATE_DISABLE);
411*f6db41e0SKamlesh Gurudasani 
412*f6db41e0SKamlesh Gurudasani 	/* Are we transitioning from no retention/enable to retention/enable? */
413*f6db41e0SKamlesh Gurudasani 	get_ret = !old_ret && new_ret;
414*f6db41e0SKamlesh Gurudasani 	get_pwr = !old_pwr && new_pwr;
415*f6db41e0SKamlesh Gurudasani 	get_en = !old_en && new_en;
416*f6db41e0SKamlesh Gurudasani 
417*f6db41e0SKamlesh Gurudasani 	/* Are we transitioning from retention/enable to no retention/enable? */
418*f6db41e0SKamlesh Gurudasani 	put_ret = old_ret && !new_ret;
419*f6db41e0SKamlesh Gurudasani 	put_pwr = old_pwr && !new_pwr;
420*f6db41e0SKamlesh Gurudasani 	put_en = old_en && !new_en;
421*f6db41e0SKamlesh Gurudasani 
422*f6db41e0SKamlesh Gurudasani 	/* Make sure our parent LPSC is enabled as necessary */
423*f6db41e0SKamlesh Gurudasani 	if ((get_en || get_ret) && ((data->flags & TI_LPSC_DEPENDS) != 0UL)) {
424*f6db41e0SKamlesh Gurudasani 		const struct ti_psc_drv_data *depends_psc = psc;
425*f6db41e0SKamlesh Gurudasani 		struct ti_device *depends_dev = dev;
426*f6db41e0SKamlesh Gurudasani 
427*f6db41e0SKamlesh Gurudasani 		if (data->depends_psc_idx != psc->psc_idx) {
428*f6db41e0SKamlesh Gurudasani 			depends_dev = ti_psc_lookup((ti_psc_idx_t) data->depends_psc_idx);
429*f6db41e0SKamlesh Gurudasani 			depends_psc = ti_to_psc_drv_data(ti_get_drv_data(depends_dev));
430*f6db41e0SKamlesh Gurudasani 		}
431*f6db41e0SKamlesh Gurudasani 		if (depends_dev == NULL) {
432*f6db41e0SKamlesh Gurudasani 			VERBOSE("ACTION FAIL: PSC_INVALID_DEP_DATA dep_pd_id=%d pd_id=%d pos=1\n",
433*f6db41e0SKamlesh Gurudasani 				psc->psc_idx, data->depends_psc_idx);
434*f6db41e0SKamlesh Gurudasani 		} else {
435*f6db41e0SKamlesh Gurudasani 			/*
436*f6db41e0SKamlesh Gurudasani 			 * Moving from a clock stop state to a clock enabled
437*f6db41e0SKamlesh Gurudasani 			 * state or from a retention disable to a retention
438*f6db41e0SKamlesh Gurudasani 			 * enabled state, bump the reference count on our
439*f6db41e0SKamlesh Gurudasani 			 * dependency.
440*f6db41e0SKamlesh Gurudasani 			 */
441*f6db41e0SKamlesh Gurudasani 			lpsc_module_get_internal(depends_dev,
442*f6db41e0SKamlesh Gurudasani 						 psc_idx2mod(depends_psc, data->depends),
443*f6db41e0SKamlesh Gurudasani 						 get_en, get_ret);
444*f6db41e0SKamlesh Gurudasani 		}
445*f6db41e0SKamlesh Gurudasani 	}
446*f6db41e0SKamlesh Gurudasani 
447*f6db41e0SKamlesh Gurudasani 	if (old_rst && !new_rst) {
448*f6db41e0SKamlesh Gurudasani 		/* Coming out of reset, bump the context loss count. */
449*f6db41e0SKamlesh Gurudasani 		module->loss_count++;
450*f6db41e0SKamlesh Gurudasani 	}
451*f6db41e0SKamlesh Gurudasani 
452*f6db41e0SKamlesh Gurudasani 	if (get_pwr) {
453*f6db41e0SKamlesh Gurudasani 		/* Make sure pd is on. */
454*f6db41e0SKamlesh Gurudasani 		ti_psc_pd_get(dev, pd);
455*f6db41e0SKamlesh Gurudasani 	}
456*f6db41e0SKamlesh Gurudasani 
457*f6db41e0SKamlesh Gurudasani 	mdctl = psc_read(dev, psc_reg(PSC_MDCTL_BASE, idx));
458*f6db41e0SKamlesh Gurudasani 	transition = (mdctl & MDSTAT_STATE_MASK) != state;
459*f6db41e0SKamlesh Gurudasani 	if (transition && (domain_reset == false)) {
460*f6db41e0SKamlesh Gurudasani 		/* Verify any previous transitions have completed */
461*f6db41e0SKamlesh Gurudasani 		ti_psc_pd_wait(dev, pd);
462*f6db41e0SKamlesh Gurudasani 
463*f6db41e0SKamlesh Gurudasani 		mdctl &= ~MDSTAT_STATE_MASK;
464*f6db41e0SKamlesh Gurudasani 		mdctl |= (uint32_t) state;
465*f6db41e0SKamlesh Gurudasani 		/* Note: This is a state machine reg */
466*f6db41e0SKamlesh Gurudasani 		psc_write(dev, mdctl, psc_reg(PSC_MDCTL_BASE, idx));
467*f6db41e0SKamlesh Gurudasani 	}
468*f6db41e0SKamlesh Gurudasani 
469*f6db41e0SKamlesh Gurudasani 	if (domain_reset == false) {
470*f6db41e0SKamlesh Gurudasani 		if (put_pwr) {
471*f6db41e0SKamlesh Gurudasani 			/* Module is ready for power down, drop ref count on pd */
472*f6db41e0SKamlesh Gurudasani 			ti_psc_pd_put(dev, pd);
473*f6db41e0SKamlesh Gurudasani 			if ((pd->use_count != 0U) && transition) {
474*f6db41e0SKamlesh Gurudasani 				/*
475*f6db41e0SKamlesh Gurudasani 				 * If ti_psc_pd_put has a use count of zero, it already
476*f6db41e0SKamlesh Gurudasani 				 * initaited the transition, otherwise we need to
477*f6db41e0SKamlesh Gurudasani 				 * do the transition ourselves.
478*f6db41e0SKamlesh Gurudasani 				 */
479*f6db41e0SKamlesh Gurudasani 				pd_initiate(dev, pd);
480*f6db41e0SKamlesh Gurudasani 			}
481*f6db41e0SKamlesh Gurudasani 		} else if (transition) {
482*f6db41e0SKamlesh Gurudasani 			/*
483*f6db41e0SKamlesh Gurudasani 			 * Initiate transition
484*f6db41e0SKamlesh Gurudasani 			 */
485*f6db41e0SKamlesh Gurudasani 			pd_initiate(dev, pd);
486*f6db41e0SKamlesh Gurudasani 		}
487*f6db41e0SKamlesh Gurudasani 	}
488*f6db41e0SKamlesh Gurudasani 
489*f6db41e0SKamlesh Gurudasani 	/* Allow our parent LPSC to be disabled as necessary */
490*f6db41e0SKamlesh Gurudasani 	if ((put_en || put_ret) && ((data->flags & TI_LPSC_DEPENDS) != 0UL)) {
491*f6db41e0SKamlesh Gurudasani 		const struct ti_psc_drv_data *depends_psc = psc;
492*f6db41e0SKamlesh Gurudasani 		struct ti_device *depends_dev = dev;
493*f6db41e0SKamlesh Gurudasani 
494*f6db41e0SKamlesh Gurudasani 		if (data->depends_psc_idx != psc->psc_idx) {
495*f6db41e0SKamlesh Gurudasani 			depends_dev = ti_psc_lookup((ti_psc_idx_t) data->depends_psc_idx);
496*f6db41e0SKamlesh Gurudasani 			depends_psc = ti_to_psc_drv_data(ti_get_drv_data(depends_dev));
497*f6db41e0SKamlesh Gurudasani 		}
498*f6db41e0SKamlesh Gurudasani 		if (depends_dev == NULL) {
499*f6db41e0SKamlesh Gurudasani 			VERBOSE("ACTION FAIL: PSC_INVALID_DEP_DATA dep_pd_id=%d pd_id=%d pos=2\n",
500*f6db41e0SKamlesh Gurudasani 				psc->psc_idx, data->depends_psc_idx);
501*f6db41e0SKamlesh Gurudasani 		} else if ((domain_reset == true) && (depends_dev == dev)) {
502*f6db41e0SKamlesh Gurudasani 			/* Ignore self dependencies during domain reset */
503*f6db41e0SKamlesh Gurudasani 		} else {
504*f6db41e0SKamlesh Gurudasani 			/*
505*f6db41e0SKamlesh Gurudasani 			 * Moving from a clock enabled state to a clock stop
506*f6db41e0SKamlesh Gurudasani 			 * state or from a retention enable to a retention
507*f6db41e0SKamlesh Gurudasani 			 * disabled state, drop the reference count on our
508*f6db41e0SKamlesh Gurudasani 			 * dependency.
509*f6db41e0SKamlesh Gurudasani 			 */
510*f6db41e0SKamlesh Gurudasani 			lpsc_module_put_internal(depends_dev,
511*f6db41e0SKamlesh Gurudasani 						 psc_idx2mod(depends_psc, data->depends),
512*f6db41e0SKamlesh Gurudasani 						 put_en, put_ret);
513*f6db41e0SKamlesh Gurudasani 		}
514*f6db41e0SKamlesh Gurudasani 	}
515*f6db41e0SKamlesh Gurudasani }
516*f6db41e0SKamlesh Gurudasani 
ti_lpsc_module_get_state(struct ti_device * dev,struct ti_lpsc_module * module)517*f6db41e0SKamlesh Gurudasani uint32_t ti_lpsc_module_get_state(struct ti_device *dev, struct ti_lpsc_module *module)
518*f6db41e0SKamlesh Gurudasani {
519*f6db41e0SKamlesh Gurudasani 	uint32_t idx = ti_lpsc_module_idx(dev, module);
520*f6db41e0SKamlesh Gurudasani 	uint8_t state;
521*f6db41e0SKamlesh Gurudasani 	uint32_t ret;
522*f6db41e0SKamlesh Gurudasani 
523*f6db41e0SKamlesh Gurudasani 	state = (uint8_t)(psc_read(dev, psc_reg(PSC_MDSTAT_BASE, idx)) & MDSTAT_STATE_MASK);
524*f6db41e0SKamlesh Gurudasani 
525*f6db41e0SKamlesh Gurudasani 	if (state == MDSTAT_STATE_SWRSTDISABLE) {
526*f6db41e0SKamlesh Gurudasani 		ret = TI_LPSC_STATE_DISABLED;
527*f6db41e0SKamlesh Gurudasani 	} else if ((state == MDSTAT_STATE_DISABLE) ||
528*f6db41e0SKamlesh Gurudasani 		   (state == MDSTAT_STATE_ENABLE) ||
529*f6db41e0SKamlesh Gurudasani 		   (state == MDSTAT_STATE_SYNCRST)) {
530*f6db41e0SKamlesh Gurudasani 		ret = TI_LPSC_STATE_ENABLED;
531*f6db41e0SKamlesh Gurudasani 	} else {
532*f6db41e0SKamlesh Gurudasani 		ret = TI_LPSC_STATE_TRANSITIONING;
533*f6db41e0SKamlesh Gurudasani 	}
534*f6db41e0SKamlesh Gurudasani 
535*f6db41e0SKamlesh Gurudasani 	return ret;
536*f6db41e0SKamlesh Gurudasani }
537*f6db41e0SKamlesh Gurudasani 
ti_lpsc_module_set_reset_iso(struct ti_device * dev,struct ti_lpsc_module * module,bool enable)538*f6db41e0SKamlesh Gurudasani void ti_lpsc_module_set_reset_iso(struct ti_device *dev, struct ti_lpsc_module *module,
539*f6db41e0SKamlesh Gurudasani 				  bool enable)
540*f6db41e0SKamlesh Gurudasani {
541*f6db41e0SKamlesh Gurudasani 	const struct ti_psc_drv_data *psc = ti_to_psc_drv_data(ti_get_drv_data(dev));
542*f6db41e0SKamlesh Gurudasani 	uint32_t idx = ti_lpsc_module_idx(dev, module);
543*f6db41e0SKamlesh Gurudasani 	const struct ti_lpsc_module_data *data = &psc->mod_data[idx];
544*f6db41e0SKamlesh Gurudasani 	bool is_enabled;
545*f6db41e0SKamlesh Gurudasani 	uint32_t mdctl;
546*f6db41e0SKamlesh Gurudasani 
547*f6db41e0SKamlesh Gurudasani 	if (0U == (data->flags & TI_LPSC_HAS_RESET_ISO)) {
548*f6db41e0SKamlesh Gurudasani 		return;
549*f6db41e0SKamlesh Gurudasani 	}
550*f6db41e0SKamlesh Gurudasani 
551*f6db41e0SKamlesh Gurudasani 	mdctl = psc_read(dev, psc_reg(PSC_MDCTL_BASE, idx));
552*f6db41e0SKamlesh Gurudasani 	is_enabled = (mdctl & MDCTL_RESET_ISO) != 0U;
553*f6db41e0SKamlesh Gurudasani 
554*f6db41e0SKamlesh Gurudasani 	if (enable != is_enabled) {
555*f6db41e0SKamlesh Gurudasani 		if (enable) {
556*f6db41e0SKamlesh Gurudasani 			mdctl |= MDCTL_RESET_ISO;
557*f6db41e0SKamlesh Gurudasani 		} else {
558*f6db41e0SKamlesh Gurudasani 			mdctl &= ~MDCTL_RESET_ISO;
559*f6db41e0SKamlesh Gurudasani 		}
560*f6db41e0SKamlesh Gurudasani 		/* Note: This is a state machine reg */
561*f6db41e0SKamlesh Gurudasani 		psc_write(dev, mdctl, psc_reg(PSC_MDCTL_BASE, idx));
562*f6db41e0SKamlesh Gurudasani 	}
563*f6db41e0SKamlesh Gurudasani }
564*f6db41e0SKamlesh Gurudasani 
ti_lpsc_module_get_reset_iso(struct ti_device * dev,struct ti_lpsc_module * module)565*f6db41e0SKamlesh Gurudasani bool ti_lpsc_module_get_reset_iso(struct ti_device *dev, struct ti_lpsc_module *module)
566*f6db41e0SKamlesh Gurudasani {
567*f6db41e0SKamlesh Gurudasani 	const struct ti_psc_drv_data *psc = ti_to_psc_drv_data(ti_get_drv_data(dev));
568*f6db41e0SKamlesh Gurudasani 	uint32_t idx = ti_lpsc_module_idx(dev, module);
569*f6db41e0SKamlesh Gurudasani 	const struct ti_lpsc_module_data *data = &psc->mod_data[idx];
570*f6db41e0SKamlesh Gurudasani 	bool ret;
571*f6db41e0SKamlesh Gurudasani 
572*f6db41e0SKamlesh Gurudasani 	if (0U == (data->flags & TI_LPSC_HAS_RESET_ISO)) {
573*f6db41e0SKamlesh Gurudasani 		ret = false;
574*f6db41e0SKamlesh Gurudasani 	} else {
575*f6db41e0SKamlesh Gurudasani 		ret = (psc_read(dev, psc_reg(PSC_MDCTL_BASE, idx)) & MDCTL_RESET_ISO) != 0U;
576*f6db41e0SKamlesh Gurudasani 	}
577*f6db41e0SKamlesh Gurudasani 	return ret;
578*f6db41e0SKamlesh Gurudasani }
579*f6db41e0SKamlesh Gurudasani 
580*f6db41e0SKamlesh Gurudasani /* Does not bump context loss count */
ti_lpsc_module_set_local_reset(struct ti_device * dev,struct ti_lpsc_module * module,bool enable)581*f6db41e0SKamlesh Gurudasani void ti_lpsc_module_set_local_reset(struct ti_device *dev, struct ti_lpsc_module *module,
582*f6db41e0SKamlesh Gurudasani 				    bool enable)
583*f6db41e0SKamlesh Gurudasani {
584*f6db41e0SKamlesh Gurudasani 	const struct ti_psc_drv_data *psc = ti_to_psc_drv_data(ti_get_drv_data(dev));
585*f6db41e0SKamlesh Gurudasani 	uint32_t idx = ti_lpsc_module_idx(dev, module);
586*f6db41e0SKamlesh Gurudasani 	const struct ti_lpsc_module_data *data = &psc->mod_data[idx];
587*f6db41e0SKamlesh Gurudasani 	bool is_enabled;
588*f6db41e0SKamlesh Gurudasani 	uint32_t mdctl;
589*f6db41e0SKamlesh Gurudasani 
590*f6db41e0SKamlesh Gurudasani 	if (0U == (data->flags & TI_LPSC_HAS_LOCAL_RESET)) {
591*f6db41e0SKamlesh Gurudasani 		return;
592*f6db41e0SKamlesh Gurudasani 	}
593*f6db41e0SKamlesh Gurudasani 
594*f6db41e0SKamlesh Gurudasani 	mdctl = psc_read(dev, (uint32_t) psc_reg(PSC_MDCTL_BASE, idx));
595*f6db41e0SKamlesh Gurudasani 	is_enabled = (mdctl & MDCTL_LRST) == 0U;
596*f6db41e0SKamlesh Gurudasani 
597*f6db41e0SKamlesh Gurudasani 	if (enable != is_enabled) {
598*f6db41e0SKamlesh Gurudasani 		VERBOSE("SET_LOCAL_RESET: psc_id=%d lpsc_id=%d enable=%d\n",
599*f6db41e0SKamlesh Gurudasani 			psc->psc_idx, idx, ((enable == true) ? 1U : 0U));
600*f6db41e0SKamlesh Gurudasani 
601*f6db41e0SKamlesh Gurudasani 		if (enable) {
602*f6db41e0SKamlesh Gurudasani 			mdctl &= ~MDCTL_LRST;
603*f6db41e0SKamlesh Gurudasani 		} else {
604*f6db41e0SKamlesh Gurudasani 			mdctl |= MDCTL_LRST;
605*f6db41e0SKamlesh Gurudasani 		}
606*f6db41e0SKamlesh Gurudasani 
607*f6db41e0SKamlesh Gurudasani 		/* Note: This is a state machine reg */
608*f6db41e0SKamlesh Gurudasani 		psc_write(dev, mdctl, psc_reg(PSC_MDCTL_BASE, idx));
609*f6db41e0SKamlesh Gurudasani 	}
610*f6db41e0SKamlesh Gurudasani }
611*f6db41e0SKamlesh Gurudasani 
ti_lpsc_module_set_module_reset(struct ti_device * dev,struct ti_lpsc_module * module,bool enable)612*f6db41e0SKamlesh Gurudasani void ti_lpsc_module_set_module_reset(struct ti_device *dev, struct ti_lpsc_module *module,
613*f6db41e0SKamlesh Gurudasani 				     bool enable)
614*f6db41e0SKamlesh Gurudasani {
615*f6db41e0SKamlesh Gurudasani 	const struct ti_psc_drv_data *psc = ti_to_psc_drv_data(ti_get_drv_data(dev));
616*f6db41e0SKamlesh Gurudasani 	uint32_t idx = ti_lpsc_module_idx(dev, module);
617*f6db41e0SKamlesh Gurudasani 	const struct ti_lpsc_module_data *data = &psc->mod_data[idx];
618*f6db41e0SKamlesh Gurudasani 	bool is_enabled;
619*f6db41e0SKamlesh Gurudasani 
620*f6db41e0SKamlesh Gurudasani 	is_enabled = module->mrst_active != 0U;
621*f6db41e0SKamlesh Gurudasani 
622*f6db41e0SKamlesh Gurudasani 	if ((enable != is_enabled) && ((data->flags & TI_LPSC_NO_MODULE_RESET) == 0U)) {
623*f6db41e0SKamlesh Gurudasani 		VERBOSE("SET_MODULE_RESET/SET_LOCAL_RESET: psc_id=%d lpsc_id=%d enable=%d\n",
624*f6db41e0SKamlesh Gurudasani 			psc->psc_idx, idx, (enable ? 1U : 0U));
625*f6db41e0SKamlesh Gurudasani 
626*f6db41e0SKamlesh Gurudasani 		if (enable) {
627*f6db41e0SKamlesh Gurudasani 			module->mrst_active = 1U;
628*f6db41e0SKamlesh Gurudasani 		} else {
629*f6db41e0SKamlesh Gurudasani 			module->mrst_active = 0U;
630*f6db41e0SKamlesh Gurudasani 		}
631*f6db41e0SKamlesh Gurudasani 
632*f6db41e0SKamlesh Gurudasani 		lpsc_module_sync_state(dev, module, false);
633*f6db41e0SKamlesh Gurudasani 		ti_lpsc_module_wait(dev, module);
634*f6db41e0SKamlesh Gurudasani 	}
635*f6db41e0SKamlesh Gurudasani }
636*f6db41e0SKamlesh Gurudasani 
ti_lpsc_module_get_local_reset(struct ti_device * dev,struct ti_lpsc_module * module)637*f6db41e0SKamlesh Gurudasani bool ti_lpsc_module_get_local_reset(struct ti_device *dev, struct ti_lpsc_module *module)
638*f6db41e0SKamlesh Gurudasani {
639*f6db41e0SKamlesh Gurudasani 	const struct ti_psc_drv_data *psc = ti_to_psc_drv_data(ti_get_drv_data(dev));
640*f6db41e0SKamlesh Gurudasani 	uint32_t idx = ti_lpsc_module_idx(dev, module);
641*f6db41e0SKamlesh Gurudasani 	const struct ti_lpsc_module_data *data = &psc->mod_data[idx];
642*f6db41e0SKamlesh Gurudasani 	bool ret;
643*f6db41e0SKamlesh Gurudasani 
644*f6db41e0SKamlesh Gurudasani 	if (0U == (data->flags & TI_LPSC_HAS_LOCAL_RESET)) {
645*f6db41e0SKamlesh Gurudasani 		ret = false;
646*f6db41e0SKamlesh Gurudasani 	} else {
647*f6db41e0SKamlesh Gurudasani 		ret = (psc_read(dev, (uint32_t) psc_reg(PSC_MDCTL_BASE, idx)) & MDCTL_LRST) == 0U;
648*f6db41e0SKamlesh Gurudasani 	}
649*f6db41e0SKamlesh Gurudasani 	return ret;
650*f6db41e0SKamlesh Gurudasani }
651*f6db41e0SKamlesh Gurudasani 
ti_lpsc_module_get_module_reset(struct ti_device * dev __unused,const struct ti_lpsc_module * module)652*f6db41e0SKamlesh Gurudasani bool ti_lpsc_module_get_module_reset(struct ti_device *dev __unused,
653*f6db41e0SKamlesh Gurudasani 				     const struct ti_lpsc_module *module)
654*f6db41e0SKamlesh Gurudasani {
655*f6db41e0SKamlesh Gurudasani 	return module->mrst_active == 1U;
656*f6db41e0SKamlesh Gurudasani }
657*f6db41e0SKamlesh Gurudasani 
ti_lpsc_module_wait(struct ti_device * dev,struct ti_lpsc_module * module)658*f6db41e0SKamlesh Gurudasani void ti_lpsc_module_wait(struct ti_device *dev, struct ti_lpsc_module *module)
659*f6db41e0SKamlesh Gurudasani {
660*f6db41e0SKamlesh Gurudasani 	const struct ti_psc_drv_data *psc = ti_to_psc_drv_data(ti_get_drv_data(dev));
661*f6db41e0SKamlesh Gurudasani 	uint32_t idx = ti_lpsc_module_idx(dev, module);
662*f6db41e0SKamlesh Gurudasani 	const struct ti_lpsc_module_data *data = &psc->mod_data[idx];
663*f6db41e0SKamlesh Gurudasani 	struct ti_psc_pd *pd = psc_idx2pd(psc, (ti_pd_idx_t) data->powerdomain);
664*f6db41e0SKamlesh Gurudasani 	uint32_t retry_count = PSC_TRANSITION_RETRY_COUNT;
665*f6db41e0SKamlesh Gurudasani 
666*f6db41e0SKamlesh Gurudasani 	ti_psc_pd_wait(dev, pd);
667*f6db41e0SKamlesh Gurudasani 
668*f6db41e0SKamlesh Gurudasani 	while ((((psc_read(dev, psc_reg(PSC_MDSTAT_BASE, idx))) & MDSTAT_BUSY_MASK) != 0U) &&
669*f6db41e0SKamlesh Gurudasani 	       (retry_count > 0U)) {
670*f6db41e0SKamlesh Gurudasani 		udelay(PSC_TRANSITION_DELAY_US);
671*f6db41e0SKamlesh Gurudasani 		retry_count--;
672*f6db41e0SKamlesh Gurudasani 	}
673*f6db41e0SKamlesh Gurudasani 	if (retry_count == 0U) {
674*f6db41e0SKamlesh Gurudasani 		VERBOSE("PSC module transition timeout: psc_id=%d lpsc_id=%d\n",
675*f6db41e0SKamlesh Gurudasani 			psc->psc_idx, idx);
676*f6db41e0SKamlesh Gurudasani 	}
677*f6db41e0SKamlesh Gurudasani 
678*f6db41e0SKamlesh Gurudasani 	/* Only wait for reset to complete if module is in use */
679*f6db41e0SKamlesh Gurudasani 	if ((module->use_count) != 0U) {
680*f6db41e0SKamlesh Gurudasani 		uint32_t mask = MDSTAT_MRSTDONE;
681*f6db41e0SKamlesh Gurudasani 
682*f6db41e0SKamlesh Gurudasani 		retry_count = PSC_TRANSITION_RETRY_COUNT;
683*f6db41e0SKamlesh Gurudasani 
684*f6db41e0SKamlesh Gurudasani 		if (!ti_lpsc_module_get_local_reset(dev, module)) {
685*f6db41e0SKamlesh Gurudasani 			mask |= MDSTAT_LRSTDONE;
686*f6db41e0SKamlesh Gurudasani 		}
687*f6db41e0SKamlesh Gurudasani 		while ((0U == ((psc_read(dev, psc_reg(PSC_MDSTAT_BASE, idx))) & mask)) &&
688*f6db41e0SKamlesh Gurudasani 		       (retry_count > 0U)) {
689*f6db41e0SKamlesh Gurudasani 			udelay(PSC_TRANSITION_DELAY_US);
690*f6db41e0SKamlesh Gurudasani 			retry_count--;
691*f6db41e0SKamlesh Gurudasani 		}
692*f6db41e0SKamlesh Gurudasani 		if (retry_count == 0U) {
693*f6db41e0SKamlesh Gurudasani 			VERBOSE("PSC module reset done timeout: psc_id=%d lpsc_id=%d\n",
694*f6db41e0SKamlesh Gurudasani 				psc->psc_idx, idx);
695*f6db41e0SKamlesh Gurudasani 		}
696*f6db41e0SKamlesh Gurudasani 	}
697*f6db41e0SKamlesh Gurudasani }
698*f6db41e0SKamlesh Gurudasani 
lpsc_module_clk_get(struct ti_device * dev,struct ti_lpsc_module * mod)699*f6db41e0SKamlesh Gurudasani static void lpsc_module_clk_get(struct ti_device *dev, struct ti_lpsc_module *mod)
700*f6db41e0SKamlesh Gurudasani {
701*f6db41e0SKamlesh Gurudasani 	const struct ti_psc_drv_data *psc = ti_to_psc_drv_data(ti_get_drv_data(dev));
702*f6db41e0SKamlesh Gurudasani 	uint32_t idx = ti_lpsc_module_idx(dev, mod);
703*f6db41e0SKamlesh Gurudasani 	const struct ti_lpsc_module_data *data = &psc->mod_data[idx];
704*f6db41e0SKamlesh Gurudasani 
705*f6db41e0SKamlesh Gurudasani 	/* Get clock dependency - currently only one clock supported */
706*f6db41e0SKamlesh Gurudasani 	if (data->clock_dep[0] != 0U) {
707*f6db41e0SKamlesh Gurudasani 		struct ti_clk *clkp = ti_clk_lookup(data->clock_dep[0]);
708*f6db41e0SKamlesh Gurudasani 
709*f6db41e0SKamlesh Gurudasani 		if (clkp != NULL) {
710*f6db41e0SKamlesh Gurudasani 			(void) ti_clk_get(clkp);
711*f6db41e0SKamlesh Gurudasani 		}
712*f6db41e0SKamlesh Gurudasani 	}
713*f6db41e0SKamlesh Gurudasani }
714*f6db41e0SKamlesh Gurudasani 
715*f6db41e0SKamlesh Gurudasani /**
716*f6db41e0SKamlesh Gurudasani  * lpsc_module_clk_put() - Disable clocks necessary for LPSC module
717*f6db41e0SKamlesh Gurudasani  * @dev: The device for this PSC.
718*f6db41e0SKamlesh Gurudasani  * @mod: The const data for the LPSC module.
719*f6db41e0SKamlesh Gurudasani  * @wait: True to wait for the module to complete transitioning
720*f6db41e0SKamlesh Gurudasani  *        before disabling clocks. Set to false when called as
721*f6db41e0SKamlesh Gurudasani  *        part of a domain reset.
722*f6db41e0SKamlesh Gurudasani  *
723*f6db41e0SKamlesh Gurudasani  * This function calls ti_clk_put on each of the clocks listed
724*f6db41e0SKamlesh Gurudasani  * under clock_dep for a given LPSC module. Some modules
725*f6db41e0SKamlesh Gurudasani  * require certain clocks to be running while the module
726*f6db41e0SKamlesh Gurudasani  * is in transition or on.
727*f6db41e0SKamlesh Gurudasani  */
lpsc_module_clk_put(struct ti_device * dev,struct ti_lpsc_module * mod,bool wait)728*f6db41e0SKamlesh Gurudasani static void lpsc_module_clk_put(struct ti_device *dev, struct ti_lpsc_module *mod,
729*f6db41e0SKamlesh Gurudasani 				bool wait)
730*f6db41e0SKamlesh Gurudasani {
731*f6db41e0SKamlesh Gurudasani 	const struct ti_psc_drv_data *psc = ti_to_psc_drv_data(ti_get_drv_data(dev));
732*f6db41e0SKamlesh Gurudasani 	uint32_t idx = ti_lpsc_module_idx(dev, mod);
733*f6db41e0SKamlesh Gurudasani 	const struct ti_lpsc_module_data *data = &psc->mod_data[idx];
734*f6db41e0SKamlesh Gurudasani 
735*f6db41e0SKamlesh Gurudasani 	/* Put clock dependency - currently only one clock supported */
736*f6db41e0SKamlesh Gurudasani 	if (data->clock_dep[0] != 0U) {
737*f6db41e0SKamlesh Gurudasani 		struct ti_clk *clkp = ti_clk_lookup(data->clock_dep[0]);
738*f6db41e0SKamlesh Gurudasani 
739*f6db41e0SKamlesh Gurudasani 		if (clkp != NULL) {
740*f6db41e0SKamlesh Gurudasani 			/*
741*f6db41e0SKamlesh Gurudasani 			 * We have to wait for the transition to complete
742*f6db41e0SKamlesh Gurudasani 			 * taking a clock away.
743*f6db41e0SKamlesh Gurudasani 			 */
744*f6db41e0SKamlesh Gurudasani 			if (wait) {
745*f6db41e0SKamlesh Gurudasani 				ti_lpsc_module_wait(dev, mod);
746*f6db41e0SKamlesh Gurudasani 			}
747*f6db41e0SKamlesh Gurudasani 			ti_clk_put(clkp);
748*f6db41e0SKamlesh Gurudasani 		}
749*f6db41e0SKamlesh Gurudasani 	}
750*f6db41e0SKamlesh Gurudasani }
751*f6db41e0SKamlesh Gurudasani 
lpsc_module_get_internal(struct ti_device * dev,struct ti_lpsc_module * module,bool use,bool ret)752*f6db41e0SKamlesh Gurudasani static void lpsc_module_get_internal(struct ti_device *dev,
753*f6db41e0SKamlesh Gurudasani 				     struct ti_lpsc_module *module,
754*f6db41e0SKamlesh Gurudasani 				     bool use, bool ret)
755*f6db41e0SKamlesh Gurudasani {
756*f6db41e0SKamlesh Gurudasani 	const struct ti_psc_drv_data *psc = ti_to_psc_drv_data(ti_get_drv_data(dev));
757*f6db41e0SKamlesh Gurudasani 	bool modify = false;
758*f6db41e0SKamlesh Gurudasani 
759*f6db41e0SKamlesh Gurudasani 	if (use) {
760*f6db41e0SKamlesh Gurudasani 		VERBOSE("MODULE_GET: psc_id=%d lpsc_id=%d use_count=%d\n",
761*f6db41e0SKamlesh Gurudasani 			psc->psc_idx, ti_lpsc_module_idx(dev, module),
762*f6db41e0SKamlesh Gurudasani 			module->use_count);
763*f6db41e0SKamlesh Gurudasani 		module->use_count++;
764*f6db41e0SKamlesh Gurudasani 		if (module->use_count == 1U) {
765*f6db41e0SKamlesh Gurudasani 			lpsc_module_clk_get(dev, module);
766*f6db41e0SKamlesh Gurudasani 			modify = true;
767*f6db41e0SKamlesh Gurudasani 		}
768*f6db41e0SKamlesh Gurudasani 	}
769*f6db41e0SKamlesh Gurudasani 
770*f6db41e0SKamlesh Gurudasani 	if (ret) {
771*f6db41e0SKamlesh Gurudasani 		VERBOSE("RETENTION_GET: psc_id=%d lpsc_id=%d ret_count=%d\n",
772*f6db41e0SKamlesh Gurudasani 			psc->psc_idx, ti_lpsc_module_idx(dev, module),
773*f6db41e0SKamlesh Gurudasani 			module->ret_count);
774*f6db41e0SKamlesh Gurudasani 		module->ret_count++;
775*f6db41e0SKamlesh Gurudasani 		if (module->ret_count == 1U) {
776*f6db41e0SKamlesh Gurudasani 			lpsc_module_clk_get(dev, module);
777*f6db41e0SKamlesh Gurudasani 			modify = true;
778*f6db41e0SKamlesh Gurudasani 		}
779*f6db41e0SKamlesh Gurudasani 	}
780*f6db41e0SKamlesh Gurudasani 
781*f6db41e0SKamlesh Gurudasani 	if (modify) {
782*f6db41e0SKamlesh Gurudasani 		lpsc_module_sync_state(dev, module, false);
783*f6db41e0SKamlesh Gurudasani 		ti_lpsc_module_wait(dev, module);
784*f6db41e0SKamlesh Gurudasani 	}
785*f6db41e0SKamlesh Gurudasani }
786*f6db41e0SKamlesh Gurudasani 
lpsc_module_put_internal(struct ti_device * dev,struct ti_lpsc_module * module,bool use,bool ret)787*f6db41e0SKamlesh Gurudasani static void lpsc_module_put_internal(struct ti_device *dev,
788*f6db41e0SKamlesh Gurudasani 				     struct ti_lpsc_module *module,
789*f6db41e0SKamlesh Gurudasani 				     bool use, bool ret)
790*f6db41e0SKamlesh Gurudasani {
791*f6db41e0SKamlesh Gurudasani 	const struct ti_psc_drv_data *psc = ti_to_psc_drv_data(ti_get_drv_data(dev));
792*f6db41e0SKamlesh Gurudasani 	bool modify = false;
793*f6db41e0SKamlesh Gurudasani 
794*f6db41e0SKamlesh Gurudasani 	if (use) {
795*f6db41e0SKamlesh Gurudasani 		VERBOSE("MODULE_PUT: psc_id=%d lpsc_id=%d use_count=%d\n",
796*f6db41e0SKamlesh Gurudasani 			psc->psc_idx, ti_lpsc_module_idx(dev, module),
797*f6db41e0SKamlesh Gurudasani 			module->use_count);
798*f6db41e0SKamlesh Gurudasani 		module->use_count--;
799*f6db41e0SKamlesh Gurudasani 		if (module->use_count == 0U) {
800*f6db41e0SKamlesh Gurudasani 			modify = true;
801*f6db41e0SKamlesh Gurudasani 		}
802*f6db41e0SKamlesh Gurudasani 	}
803*f6db41e0SKamlesh Gurudasani 
804*f6db41e0SKamlesh Gurudasani 	if (ret) {
805*f6db41e0SKamlesh Gurudasani 		VERBOSE("RETENTION_PUT: psc_id=%d lpsc_id=%d ret_count=%d\n",
806*f6db41e0SKamlesh Gurudasani 			psc->psc_idx, ti_lpsc_module_idx(dev, module),
807*f6db41e0SKamlesh Gurudasani 			module->ret_count);
808*f6db41e0SKamlesh Gurudasani 		module->ret_count--;
809*f6db41e0SKamlesh Gurudasani 		if (module->ret_count == 0U) {
810*f6db41e0SKamlesh Gurudasani 			modify = true;
811*f6db41e0SKamlesh Gurudasani 		}
812*f6db41e0SKamlesh Gurudasani 	}
813*f6db41e0SKamlesh Gurudasani 
814*f6db41e0SKamlesh Gurudasani 	if (modify) {
815*f6db41e0SKamlesh Gurudasani 		lpsc_module_sync_state(dev, module, false);
816*f6db41e0SKamlesh Gurudasani 		if ((module->use_count == 0U) && use) {
817*f6db41e0SKamlesh Gurudasani 			lpsc_module_clk_put(dev, module, true);
818*f6db41e0SKamlesh Gurudasani 		}
819*f6db41e0SKamlesh Gurudasani 		if ((module->ret_count == 0U) && ret) {
820*f6db41e0SKamlesh Gurudasani 			lpsc_module_clk_put(dev, module, true);
821*f6db41e0SKamlesh Gurudasani 		}
822*f6db41e0SKamlesh Gurudasani 	}
823*f6db41e0SKamlesh Gurudasani }
824*f6db41e0SKamlesh Gurudasani 
ti_lpsc_module_get(struct ti_device * dev,struct ti_lpsc_module * module)825*f6db41e0SKamlesh Gurudasani void ti_lpsc_module_get(struct ti_device *dev, struct ti_lpsc_module *module)
826*f6db41e0SKamlesh Gurudasani {
827*f6db41e0SKamlesh Gurudasani 	lpsc_module_get_internal(dev, module, true, false);
828*f6db41e0SKamlesh Gurudasani }
829*f6db41e0SKamlesh Gurudasani 
ti_lpsc_module_put(struct ti_device * dev,struct ti_lpsc_module * module)830*f6db41e0SKamlesh Gurudasani void ti_lpsc_module_put(struct ti_device *dev, struct ti_lpsc_module *module)
831*f6db41e0SKamlesh Gurudasani {
832*f6db41e0SKamlesh Gurudasani 	lpsc_module_put_internal(dev, module, true, false);
833*f6db41e0SKamlesh Gurudasani }
834*f6db41e0SKamlesh Gurudasani 
ti_lpsc_module_ret_get(struct ti_device * dev,struct ti_lpsc_module * module)835*f6db41e0SKamlesh Gurudasani void ti_lpsc_module_ret_get(struct ti_device *dev, struct ti_lpsc_module *module)
836*f6db41e0SKamlesh Gurudasani {
837*f6db41e0SKamlesh Gurudasani 	lpsc_module_get_internal(dev, module, false, true);
838*f6db41e0SKamlesh Gurudasani }
839*f6db41e0SKamlesh Gurudasani 
ti_lpsc_module_ret_put(struct ti_device * dev,struct ti_lpsc_module * module)840*f6db41e0SKamlesh Gurudasani void ti_lpsc_module_ret_put(struct ti_device *dev, struct ti_lpsc_module *module)
841*f6db41e0SKamlesh Gurudasani {
842*f6db41e0SKamlesh Gurudasani 	lpsc_module_put_internal(dev, module, false, true);
843*f6db41e0SKamlesh Gurudasani }
844*f6db41e0SKamlesh Gurudasani 
845*f6db41e0SKamlesh Gurudasani /* Drop power up ref counts */
psc_pd_drop_pwr_up_ref(struct ti_device * dev)846*f6db41e0SKamlesh Gurudasani static void psc_pd_drop_pwr_up_ref(struct ti_device *dev)
847*f6db41e0SKamlesh Gurudasani {
848*f6db41e0SKamlesh Gurudasani 	const struct ti_psc_drv_data *psc = ti_to_psc_drv_data(ti_get_drv_data(dev));
849*f6db41e0SKamlesh Gurudasani 	ti_pd_idx_t idx;
850*f6db41e0SKamlesh Gurudasani 
851*f6db41e0SKamlesh Gurudasani 	for (idx = 0U; idx < psc->pd_count; idx++) {
852*f6db41e0SKamlesh Gurudasani 		struct ti_psc_pd *pd = psc_idx2pd(psc, idx);
853*f6db41e0SKamlesh Gurudasani 
854*f6db41e0SKamlesh Gurudasani 		if ((pd->pwr_up_enabled) != false) {
855*f6db41e0SKamlesh Gurudasani 			pd->pwr_up_enabled = false;
856*f6db41e0SKamlesh Gurudasani 			ti_psc_pd_put(dev, pd);
857*f6db41e0SKamlesh Gurudasani 		}
858*f6db41e0SKamlesh Gurudasani 	}
859*f6db41e0SKamlesh Gurudasani }
860*f6db41e0SKamlesh Gurudasani 
ti_psc_lookup(ti_psc_idx_t id)861*f6db41e0SKamlesh Gurudasani struct ti_device *ti_psc_lookup(ti_psc_idx_t id)
862*f6db41e0SKamlesh Gurudasani {
863*f6db41e0SKamlesh Gurudasani 	struct ti_device *dev;
864*f6db41e0SKamlesh Gurudasani 
865*f6db41e0SKamlesh Gurudasani 	dev = psc_devs;
866*f6db41e0SKamlesh Gurudasani 	while (dev != NULL) {
867*f6db41e0SKamlesh Gurudasani 		const struct ti_psc_drv_data *psc;
868*f6db41e0SKamlesh Gurudasani 
869*f6db41e0SKamlesh Gurudasani 		psc = ti_to_psc_drv_data(ti_get_drv_data(dev));
870*f6db41e0SKamlesh Gurudasani 
871*f6db41e0SKamlesh Gurudasani 		if ((ti_psc_idx_t) psc->psc_idx == id) {
872*f6db41e0SKamlesh Gurudasani 			break;
873*f6db41e0SKamlesh Gurudasani 		}
874*f6db41e0SKamlesh Gurudasani 
875*f6db41e0SKamlesh Gurudasani 		dev = psc->data->next;
876*f6db41e0SKamlesh Gurudasani 	}
877*f6db41e0SKamlesh Gurudasani 
878*f6db41e0SKamlesh Gurudasani 	return dev;
879*f6db41e0SKamlesh Gurudasani }
880*f6db41e0SKamlesh Gurudasani 
ti_psc_lookup_pd(struct ti_device * dev,ti_pd_idx_t id)881*f6db41e0SKamlesh Gurudasani struct ti_psc_pd *ti_psc_lookup_pd(struct ti_device *dev, ti_pd_idx_t id)
882*f6db41e0SKamlesh Gurudasani {
883*f6db41e0SKamlesh Gurudasani 	const struct ti_psc_drv_data *psc = ti_to_psc_drv_data(ti_get_drv_data(dev));
884*f6db41e0SKamlesh Gurudasani 	struct ti_psc_pd *pd = NULL;
885*f6db41e0SKamlesh Gurudasani 
886*f6db41e0SKamlesh Gurudasani 	if ((id < psc->pd_count) &&
887*f6db41e0SKamlesh Gurudasani 	    ((psc->pd_data[id].flags & TI_PSC_PD_EXISTS) != 0U)) {
888*f6db41e0SKamlesh Gurudasani 		pd = psc_idx2pd(psc, id);
889*f6db41e0SKamlesh Gurudasani 	}
890*f6db41e0SKamlesh Gurudasani 	return pd;
891*f6db41e0SKamlesh Gurudasani }
892*f6db41e0SKamlesh Gurudasani 
ti_psc_lookup_lpsc(struct ti_device * dev,ti_pd_idx_t id)893*f6db41e0SKamlesh Gurudasani struct ti_lpsc_module *ti_psc_lookup_lpsc(struct ti_device *dev, ti_pd_idx_t id)
894*f6db41e0SKamlesh Gurudasani {
895*f6db41e0SKamlesh Gurudasani 	const struct ti_psc_drv_data *psc = ti_to_psc_drv_data(ti_get_drv_data(dev));
896*f6db41e0SKamlesh Gurudasani 	struct ti_lpsc_module *mod = NULL;
897*f6db41e0SKamlesh Gurudasani 
898*f6db41e0SKamlesh Gurudasani 	if ((id < psc->module_count) &&
899*f6db41e0SKamlesh Gurudasani 	    ((psc->mod_data[id].flags & TI_LPSC_MODULE_EXISTS) != 0U)) {
900*f6db41e0SKamlesh Gurudasani 		mod = psc_idx2mod(psc, id);
901*f6db41e0SKamlesh Gurudasani 	}
902*f6db41e0SKamlesh Gurudasani 	return mod;
903*f6db41e0SKamlesh Gurudasani }
904*f6db41e0SKamlesh Gurudasani 
905*f6db41e0SKamlesh Gurudasani /**
906*f6db41e0SKamlesh Gurudasani  * psc_initialize_pds() - Initialize all the PSC powerdomains.
907*f6db41e0SKamlesh Gurudasani  *
908*f6db41e0SKamlesh Gurudasani  * This initializes the powerdomains by waiting for them to finish any
909*f6db41e0SKamlesh Gurudasani  * active transitions, reading their state, and synchronizing it with the
910*f6db41e0SKamlesh Gurudasani  * in memory state.
911*f6db41e0SKamlesh Gurudasani  */
psc_initialize_pds(struct ti_device * dev)912*f6db41e0SKamlesh Gurudasani static void psc_initialize_pds(struct ti_device *dev)
913*f6db41e0SKamlesh Gurudasani {
914*f6db41e0SKamlesh Gurudasani 	const struct ti_psc_drv_data *psc = ti_to_psc_drv_data(ti_get_drv_data(dev));
915*f6db41e0SKamlesh Gurudasani 	ti_pd_idx_t idx;
916*f6db41e0SKamlesh Gurudasani 	struct ti_psc_pd *pd;
917*f6db41e0SKamlesh Gurudasani 	uint8_t state;
918*f6db41e0SKamlesh Gurudasani 
919*f6db41e0SKamlesh Gurudasani 	/* First pass, find out which domains are on */
920*f6db41e0SKamlesh Gurudasani 	for (idx = 0U; idx < psc->pd_count; idx++) {
921*f6db41e0SKamlesh Gurudasani 		pd = psc_idx2pd(psc, idx);
922*f6db41e0SKamlesh Gurudasani 
923*f6db41e0SKamlesh Gurudasani 		if (0U == (psc->pd_data[idx].flags & TI_PSC_PD_EXISTS)) {
924*f6db41e0SKamlesh Gurudasani 			continue;
925*f6db41e0SKamlesh Gurudasani 		}
926*f6db41e0SKamlesh Gurudasani 
927*f6db41e0SKamlesh Gurudasani 		VERBOSE("PD_INIT: psc_id=%d lpsc_id=%d\n", psc->psc_idx, idx);
928*f6db41e0SKamlesh Gurudasani 		ti_psc_pd_wait(dev, pd);
929*f6db41e0SKamlesh Gurudasani 		state = (uint8_t) psc_read(dev, psc_reg(PSC_PDSTAT_BASE, (uint32_t) idx));
930*f6db41e0SKamlesh Gurudasani 		state &= (uint8_t) PDSTAT_STATE_MASK;
931*f6db41e0SKamlesh Gurudasani 
932*f6db41e0SKamlesh Gurudasani 		/*
933*f6db41e0SKamlesh Gurudasani 		 * Mark a PD as power up in use so we don't power everything
934*f6db41e0SKamlesh Gurudasani 		 * off before PMMC startup is complete
935*f6db41e0SKamlesh Gurudasani 		 */
936*f6db41e0SKamlesh Gurudasani 		pd->pwr_up_enabled =  ((state == PDCTL_STATE_ON) ||
937*f6db41e0SKamlesh Gurudasani 				       ((psc->pd_data[idx].flags & TI_PSC_PD_ALWAYSON) != 0U));
938*f6db41e0SKamlesh Gurudasani 	}
939*f6db41e0SKamlesh Gurudasani 
940*f6db41e0SKamlesh Gurudasani 	/* Second pass, sync use count and impossible hardware states */
941*f6db41e0SKamlesh Gurudasani 	for (idx = 0U; idx < psc->pd_count; idx++) {
942*f6db41e0SKamlesh Gurudasani 		pd = psc_idx2pd(psc, idx);
943*f6db41e0SKamlesh Gurudasani 
944*f6db41e0SKamlesh Gurudasani 		if (pd->pwr_up_enabled != false) {
945*f6db41e0SKamlesh Gurudasani 			ti_psc_pd_get(dev, pd);
946*f6db41e0SKamlesh Gurudasani 		}
947*f6db41e0SKamlesh Gurudasani 	}
948*f6db41e0SKamlesh Gurudasani }
949*f6db41e0SKamlesh Gurudasani 
950*f6db41e0SKamlesh Gurudasani /**
951*f6db41e0SKamlesh Gurudasani  * psc_uninitialize_pds() - Unititialize all the power domains of a PSC.
952*f6db41e0SKamlesh Gurudasani  * @dev: The device associated with this PSC.
953*f6db41e0SKamlesh Gurudasani  *
954*f6db41e0SKamlesh Gurudasani  * This sets all the power domains in a PSC to a pre-initialized state
955*f6db41e0SKamlesh Gurudasani  * in preparation for the reset of it's reset domain. Because power
956*f6db41e0SKamlesh Gurudasani  * domains can only have dependencies on other domains within the same
957*f6db41e0SKamlesh Gurudasani  * PSC, this just means ensuring that the clock references are dropped.
958*f6db41e0SKamlesh Gurudasani  */
psc_uninitialize_pds(struct ti_device * dev)959*f6db41e0SKamlesh Gurudasani static void psc_uninitialize_pds(struct ti_device *dev)
960*f6db41e0SKamlesh Gurudasani {
961*f6db41e0SKamlesh Gurudasani 	const struct ti_psc_drv_data *psc = ti_to_psc_drv_data(ti_get_drv_data(dev));
962*f6db41e0SKamlesh Gurudasani 	ti_pd_idx_t idx;
963*f6db41e0SKamlesh Gurudasani 
964*f6db41e0SKamlesh Gurudasani 	for (idx = 0U; idx < psc->pd_count; idx++) {
965*f6db41e0SKamlesh Gurudasani 		struct ti_psc_pd *pd = psc_idx2pd(psc, idx);
966*f6db41e0SKamlesh Gurudasani 
967*f6db41e0SKamlesh Gurudasani 		if (((psc->pd_data[idx].flags & TI_PSC_PD_EXISTS) != 0U) &&
968*f6db41e0SKamlesh Gurudasani 		    (pd->use_count != 0U) &&
969*f6db41e0SKamlesh Gurudasani 		    ((psc->pd_data[idx].flags & TI_PSC_PD_ALWAYSON) == 0U)) {
970*f6db41e0SKamlesh Gurudasani 			psc_pd_clk_put(&psc->pd_data[idx]);
971*f6db41e0SKamlesh Gurudasani 		}
972*f6db41e0SKamlesh Gurudasani 
973*f6db41e0SKamlesh Gurudasani 		pd->use_count = 0U;
974*f6db41e0SKamlesh Gurudasani 		pd->pwr_up_enabled = false;
975*f6db41e0SKamlesh Gurudasani 	}
976*f6db41e0SKamlesh Gurudasani 
977*f6db41e0SKamlesh Gurudasani 	psc->data->pds_enabled = 0U;
978*f6db41e0SKamlesh Gurudasani }
979*f6db41e0SKamlesh Gurudasani 
980*f6db41e0SKamlesh Gurudasani /* Drop power up ref counts */
ti_psc_drop_pwr_up_ref(void)981*f6db41e0SKamlesh Gurudasani void ti_psc_drop_pwr_up_ref(void)
982*f6db41e0SKamlesh Gurudasani {
983*f6db41e0SKamlesh Gurudasani 	struct ti_device *dev = psc_devs;
984*f6db41e0SKamlesh Gurudasani 	const struct ti_psc_drv_data *psc;
985*f6db41e0SKamlesh Gurudasani 	ti_lpsc_idx_t idx;
986*f6db41e0SKamlesh Gurudasani 
987*f6db41e0SKamlesh Gurudasani 	while (dev != NULL) {
988*f6db41e0SKamlesh Gurudasani 		psc = ti_to_psc_drv_data(ti_get_drv_data(dev));
989*f6db41e0SKamlesh Gurudasani 
990*f6db41e0SKamlesh Gurudasani 		for (idx = 0U; idx < psc->module_count; idx++) {
991*f6db41e0SKamlesh Gurudasani 			struct ti_lpsc_module *mod = psc_idx2mod(psc, idx);
992*f6db41e0SKamlesh Gurudasani 
993*f6db41e0SKamlesh Gurudasani 			if (mod->pwr_up_enabled != 0U) {
994*f6db41e0SKamlesh Gurudasani 				mod->pwr_up_enabled = 0U;
995*f6db41e0SKamlesh Gurudasani 				ti_lpsc_module_put(dev, mod);
996*f6db41e0SKamlesh Gurudasani 			}
997*f6db41e0SKamlesh Gurudasani 			if (mod->pwr_up_ret != 0U) {
998*f6db41e0SKamlesh Gurudasani 				mod->pwr_up_ret = 0U;
999*f6db41e0SKamlesh Gurudasani 				ti_lpsc_module_ret_put(dev, mod);
1000*f6db41e0SKamlesh Gurudasani 			}
1001*f6db41e0SKamlesh Gurudasani 		}
1002*f6db41e0SKamlesh Gurudasani 		dev = psc->data->next;
1003*f6db41e0SKamlesh Gurudasani 	}
1004*f6db41e0SKamlesh Gurudasani }
1005*f6db41e0SKamlesh Gurudasani 
1006*f6db41e0SKamlesh Gurudasani /**
1007*f6db41e0SKamlesh Gurudasani  * psc_initialize_modules() - Initialize all the PSC modules.
1008*f6db41e0SKamlesh Gurudasani  *
1009*f6db41e0SKamlesh Gurudasani  * This initializes the modules by waiting for them to finish any active
1010*f6db41e0SKamlesh Gurudasani  * transitions and reading their state.
1011*f6db41e0SKamlesh Gurudasani  */
psc_initialize_modules(struct ti_device * dev)1012*f6db41e0SKamlesh Gurudasani static void psc_initialize_modules(struct ti_device *dev)
1013*f6db41e0SKamlesh Gurudasani {
1014*f6db41e0SKamlesh Gurudasani 	const struct ti_psc_drv_data *psc = ti_to_psc_drv_data(ti_get_drv_data(dev));
1015*f6db41e0SKamlesh Gurudasani 	ti_lpsc_idx_t idx;
1016*f6db41e0SKamlesh Gurudasani 
1017*f6db41e0SKamlesh Gurudasani 	/* First pass, find out which modules are enabled */
1018*f6db41e0SKamlesh Gurudasani 	for (idx = 0U; idx < psc->module_count; idx++) {
1019*f6db41e0SKamlesh Gurudasani 		struct ti_lpsc_module *mod = psc_idx2mod(psc, idx);
1020*f6db41e0SKamlesh Gurudasani 		uint32_t val;
1021*f6db41e0SKamlesh Gurudasani 		uint32_t retry_count;
1022*f6db41e0SKamlesh Gurudasani 
1023*f6db41e0SKamlesh Gurudasani 		if (0U == (psc->mod_data[idx].flags & TI_LPSC_MODULE_EXISTS)) {
1024*f6db41e0SKamlesh Gurudasani 			continue;
1025*f6db41e0SKamlesh Gurudasani 		}
1026*f6db41e0SKamlesh Gurudasani 
1027*f6db41e0SKamlesh Gurudasani 		retry_count = PSC_TRANSITION_RETRY_COUNT;
1028*f6db41e0SKamlesh Gurudasani 		while ((((psc_read(dev, psc_reg(PSC_MDSTAT_BASE,
1029*f6db41e0SKamlesh Gurudasani 						(uint32_t) idx))) &
1030*f6db41e0SKamlesh Gurudasani 						MDSTAT_BUSY_MASK) != 0U) &&
1031*f6db41e0SKamlesh Gurudasani 						(retry_count > 0U)) {
1032*f6db41e0SKamlesh Gurudasani 			udelay(PSC_TRANSITION_DELAY_US);
1033*f6db41e0SKamlesh Gurudasani 			retry_count--;
1034*f6db41e0SKamlesh Gurudasani 		}
1035*f6db41e0SKamlesh Gurudasani 		if (retry_count == 0U) {
1036*f6db41e0SKamlesh Gurudasani 			VERBOSE("PSC module busy timeout: psc_id=%d lpsc_id=%d\n",
1037*f6db41e0SKamlesh Gurudasani 				psc->psc_idx, idx);
1038*f6db41e0SKamlesh Gurudasani 		}
1039*f6db41e0SKamlesh Gurudasani 
1040*f6db41e0SKamlesh Gurudasani 		val = psc_read(dev, psc_reg(PSC_MDSTAT_BASE, (uint32_t) idx));
1041*f6db41e0SKamlesh Gurudasani 		val &= MDSTAT_STATE_MASK;
1042*f6db41e0SKamlesh Gurudasani 
1043*f6db41e0SKamlesh Gurudasani 		/* Ref count as if we are moving out of off state */
1044*f6db41e0SKamlesh Gurudasani 		mod->sw_state = MDSTAT_STATE_SWRSTDISABLE;
1045*f6db41e0SKamlesh Gurudasani 		mod->sw_mrst_ret = false;
1046*f6db41e0SKamlesh Gurudasani 
1047*f6db41e0SKamlesh Gurudasani 		if ((val == MDSTAT_STATE_ENABLE) || (val == MDSTAT_STATE_SYNCRST)) {
1048*f6db41e0SKamlesh Gurudasani 			mod->pwr_up_enabled = 1U;
1049*f6db41e0SKamlesh Gurudasani 			mod->pwr_up_ret = 1U;
1050*f6db41e0SKamlesh Gurudasani 		} else if (val == MDSTAT_STATE_DISABLE) {
1051*f6db41e0SKamlesh Gurudasani 			mod->pwr_up_enabled = 0U;
1052*f6db41e0SKamlesh Gurudasani 			mod->pwr_up_ret = 1U;
1053*f6db41e0SKamlesh Gurudasani 		} else if (val == MDSTAT_STATE_SWRSTDISABLE) {
1054*f6db41e0SKamlesh Gurudasani 			mod->pwr_up_enabled = 0U;
1055*f6db41e0SKamlesh Gurudasani 			mod->pwr_up_ret = 0U;
1056*f6db41e0SKamlesh Gurudasani 		} else {
1057*f6db41e0SKamlesh Gurudasani 			/* Invalid initial state, try turning everything on */
1058*f6db41e0SKamlesh Gurudasani 			mod->pwr_up_ret = 1U;
1059*f6db41e0SKamlesh Gurudasani 			mod->pwr_up_enabled = 1U;
1060*f6db41e0SKamlesh Gurudasani 		}
1061*f6db41e0SKamlesh Gurudasani 	}
1062*f6db41e0SKamlesh Gurudasani }
1063*f6db41e0SKamlesh Gurudasani 
1064*f6db41e0SKamlesh Gurudasani /**
1065*f6db41e0SKamlesh Gurudasani  * psc_initialize_modules_finish() - Finish initializing all the PSC modules.
1066*f6db41e0SKamlesh Gurudasani  *
1067*f6db41e0SKamlesh Gurudasani  * This finishes the initialization of modules by synchronizing their
1068*f6db41e0SKamlesh Gurudasani  * state with the in memory state.
1069*f6db41e0SKamlesh Gurudasani  */
psc_initialize_modules_finish(struct ti_device * dev)1070*f6db41e0SKamlesh Gurudasani static void psc_initialize_modules_finish(struct ti_device *dev)
1071*f6db41e0SKamlesh Gurudasani {
1072*f6db41e0SKamlesh Gurudasani 	const struct ti_psc_drv_data *psc = ti_to_psc_drv_data(ti_get_drv_data(dev));
1073*f6db41e0SKamlesh Gurudasani 	ti_lpsc_idx_t idx;
1074*f6db41e0SKamlesh Gurudasani 
1075*f6db41e0SKamlesh Gurudasani 	/* Second pass, sync ref counts */
1076*f6db41e0SKamlesh Gurudasani 	for (idx = 0U; idx < psc->module_count; idx++) {
1077*f6db41e0SKamlesh Gurudasani 		struct ti_lpsc_module *mod = psc_idx2mod(psc, idx);
1078*f6db41e0SKamlesh Gurudasani 
1079*f6db41e0SKamlesh Gurudasani 		lpsc_module_get_internal(dev, mod, (mod->pwr_up_enabled != 0U),
1080*f6db41e0SKamlesh Gurudasani 					 (mod->pwr_up_ret != 0U));
1081*f6db41e0SKamlesh Gurudasani 	}
1082*f6db41e0SKamlesh Gurudasani 
1083*f6db41e0SKamlesh Gurudasani 	psc_pd_drop_pwr_up_ref(dev);
1084*f6db41e0SKamlesh Gurudasani }
1085*f6db41e0SKamlesh Gurudasani 
1086*f6db41e0SKamlesh Gurudasani /**
1087*f6db41e0SKamlesh Gurudasani  * psc_uninitialize_modules() - Unititialize all the LPSC modules of a PSC.
1088*f6db41e0SKamlesh Gurudasani  * @dev: The device associated with this PSC.
1089*f6db41e0SKamlesh Gurudasani  *
1090*f6db41e0SKamlesh Gurudasani  * This sets all the LPSC modules in a PSC to a pre-initialized state
1091*f6db41e0SKamlesh Gurudasani  * in preparation for the reset of it's reset domain. Because LPSC
1092*f6db41e0SKamlesh Gurudasani  * modules can have dependencies on other domains, those dependencies
1093*f6db41e0SKamlesh Gurudasani  * need to be droppe as appropriate. Any clock dependencies are also
1094*f6db41e0SKamlesh Gurudasani  * dropped.
1095*f6db41e0SKamlesh Gurudasani  */
psc_uninitialize_modules(struct ti_device * dev)1096*f6db41e0SKamlesh Gurudasani static void psc_uninitialize_modules(struct ti_device *dev)
1097*f6db41e0SKamlesh Gurudasani {
1098*f6db41e0SKamlesh Gurudasani 	const struct ti_psc_drv_data *psc = ti_to_psc_drv_data(ti_get_drv_data(dev));
1099*f6db41e0SKamlesh Gurudasani 	ti_lpsc_idx_t idx;
1100*f6db41e0SKamlesh Gurudasani 
1101*f6db41e0SKamlesh Gurudasani 	/* First pass, find out which modules are enabled */
1102*f6db41e0SKamlesh Gurudasani 	for (idx = 0U; idx < psc->module_count; idx++) {
1103*f6db41e0SKamlesh Gurudasani 		struct ti_lpsc_module *mod = psc_idx2mod(psc, idx);
1104*f6db41e0SKamlesh Gurudasani 
1105*f6db41e0SKamlesh Gurudasani 		if ((psc->mod_data[idx].flags & TI_LPSC_MODULE_EXISTS) == 0U) {
1106*f6db41e0SKamlesh Gurudasani 			continue;
1107*f6db41e0SKamlesh Gurudasani 		}
1108*f6db41e0SKamlesh Gurudasani 
1109*f6db41e0SKamlesh Gurudasani 		if (mod->use_count != 0U) {
1110*f6db41e0SKamlesh Gurudasani 			lpsc_module_clk_put(dev, mod, false);
1111*f6db41e0SKamlesh Gurudasani 		}
1112*f6db41e0SKamlesh Gurudasani 		if (mod->ret_count != 0U) {
1113*f6db41e0SKamlesh Gurudasani 			lpsc_module_clk_put(dev, mod, false);
1114*f6db41e0SKamlesh Gurudasani 		}
1115*f6db41e0SKamlesh Gurudasani 
1116*f6db41e0SKamlesh Gurudasani 		mod->use_count = 0U;
1117*f6db41e0SKamlesh Gurudasani 		mod->ret_count = 0U;
1118*f6db41e0SKamlesh Gurudasani 		mod->pwr_up_enabled = 0U;
1119*f6db41e0SKamlesh Gurudasani 		mod->pwr_up_ret = 0U;
1120*f6db41e0SKamlesh Gurudasani 
1121*f6db41e0SKamlesh Gurudasani 		lpsc_module_sync_state(dev, mod, true);
1122*f6db41e0SKamlesh Gurudasani 		mod->sw_state = MDSTAT_STATE_SWRSTDISABLE;
1123*f6db41e0SKamlesh Gurudasani 		mod->sw_mrst_ret = false;
1124*f6db41e0SKamlesh Gurudasani 	}
1125*f6db41e0SKamlesh Gurudasani }
1126*f6db41e0SKamlesh Gurudasani 
1127*f6db41e0SKamlesh Gurudasani /**
1128*f6db41e0SKamlesh Gurudasani  * psc_module_deps_ready() - Check if PSCs we depend on have completed their initial config
1129*f6db41e0SKamlesh Gurudasani  *
1130*f6db41e0SKamlesh Gurudasani  * PSCs can have domains that depend on domains in other PSCs. We break up
1131*f6db41e0SKamlesh Gurudasani  * initialization into two stages because PSCs can have cross dependencies.
1132*f6db41e0SKamlesh Gurudasani  * Once all PSCs in a cross dependency set have completed, each one can
1133*f6db41e0SKamlesh Gurudasani  * move to the second stage of initialization. We use the -EAGAIN system
1134*f6db41e0SKamlesh Gurudasani  * to manage this.
1135*f6db41e0SKamlesh Gurudasani  *
1136*f6db41e0SKamlesh Gurudasani  * Return: 0 on success, <0 on failure.
1137*f6db41e0SKamlesh Gurudasani  */
psc_module_deps_ready(struct ti_device * dev)1138*f6db41e0SKamlesh Gurudasani static int32_t psc_module_deps_ready(struct ti_device *dev)
1139*f6db41e0SKamlesh Gurudasani {
1140*f6db41e0SKamlesh Gurudasani 	const struct ti_psc_drv_data *psc = ti_to_psc_drv_data(ti_get_drv_data(dev));
1141*f6db41e0SKamlesh Gurudasani 	uint32_t idx;
1142*f6db41e0SKamlesh Gurudasani 	ti_psc_idx_t id;
1143*f6db41e0SKamlesh Gurudasani 
1144*f6db41e0SKamlesh Gurudasani 	for (idx = 0; idx < psc->module_count; idx++) {
1145*f6db41e0SKamlesh Gurudasani 		if (((psc->mod_data[idx].flags & TI_LPSC_DEPENDS) != 0UL) &&
1146*f6db41e0SKamlesh Gurudasani 		    (psc->mod_data[idx].depends_psc_idx != psc->psc_idx)) {
1147*f6db41e0SKamlesh Gurudasani 			id = (ti_psc_idx_t) psc->mod_data[idx].depends_psc_idx;
1148*f6db41e0SKamlesh Gurudasani 			if (ti_psc_lookup(id) == NULL) {
1149*f6db41e0SKamlesh Gurudasani 				return -EAGAIN;
1150*f6db41e0SKamlesh Gurudasani 			}
1151*f6db41e0SKamlesh Gurudasani 		}
1152*f6db41e0SKamlesh Gurudasani 	}
1153*f6db41e0SKamlesh Gurudasani 
1154*f6db41e0SKamlesh Gurudasani 	return 0;
1155*f6db41e0SKamlesh Gurudasani }
1156*f6db41e0SKamlesh Gurudasani 
psc_pre_init(struct ti_device * dev)1157*f6db41e0SKamlesh Gurudasani static int32_t psc_pre_init(struct ti_device *dev)
1158*f6db41e0SKamlesh Gurudasani {
1159*f6db41e0SKamlesh Gurudasani 	const struct ti_drv_data *data;
1160*f6db41e0SKamlesh Gurudasani 	const struct ti_psc_drv_data *psc;
1161*f6db41e0SKamlesh Gurudasani 
1162*f6db41e0SKamlesh Gurudasani 	data = ti_get_drv_data(dev);
1163*f6db41e0SKamlesh Gurudasani 	psc = ti_to_psc_drv_data(data);
1164*f6db41e0SKamlesh Gurudasani 
1165*f6db41e0SKamlesh Gurudasani 	/* Only perform initial configuration if it has not been completed */
1166*f6db41e0SKamlesh Gurudasani 	if (ti_psc_lookup((ti_psc_idx_t) psc->psc_idx) == NULL) {
1167*f6db41e0SKamlesh Gurudasani 		if (psc->base == 0U) {
1168*f6db41e0SKamlesh Gurudasani 			return -EINVAL;
1169*f6db41e0SKamlesh Gurudasani 		}
1170*f6db41e0SKamlesh Gurudasani 
1171*f6db41e0SKamlesh Gurudasani 		psc_initialize_pds(dev);
1172*f6db41e0SKamlesh Gurudasani 		psc_initialize_modules(dev);
1173*f6db41e0SKamlesh Gurudasani 
1174*f6db41e0SKamlesh Gurudasani 		/* This marks initial config as complete */
1175*f6db41e0SKamlesh Gurudasani 		psc->data->next = psc_devs;
1176*f6db41e0SKamlesh Gurudasani 		psc_devs = dev;
1177*f6db41e0SKamlesh Gurudasani 	}
1178*f6db41e0SKamlesh Gurudasani 
1179*f6db41e0SKamlesh Gurudasani 	return 0;
1180*f6db41e0SKamlesh Gurudasani }
1181*f6db41e0SKamlesh Gurudasani 
psc_post_init(struct ti_device * dev)1182*f6db41e0SKamlesh Gurudasani static int32_t psc_post_init(struct ti_device *dev)
1183*f6db41e0SKamlesh Gurudasani {
1184*f6db41e0SKamlesh Gurudasani 	int32_t ret;
1185*f6db41e0SKamlesh Gurudasani 
1186*f6db41e0SKamlesh Gurudasani 	ret = psc_module_deps_ready(dev);
1187*f6db41e0SKamlesh Gurudasani 
1188*f6db41e0SKamlesh Gurudasani 	if (ret == 0) {
1189*f6db41e0SKamlesh Gurudasani 		psc_initialize_modules_finish(dev);
1190*f6db41e0SKamlesh Gurudasani 	}
1191*f6db41e0SKamlesh Gurudasani 
1192*f6db41e0SKamlesh Gurudasani 	return ret;
1193*f6db41e0SKamlesh Gurudasani }
1194*f6db41e0SKamlesh Gurudasani 
1195*f6db41e0SKamlesh Gurudasani /**
1196*f6db41e0SKamlesh Gurudasani  * psc_uninit() - Uninitialize this PSC.
1197*f6db41e0SKamlesh Gurudasani  * @dev: The device associated with this PSC.
1198*f6db41e0SKamlesh Gurudasani  *
1199*f6db41e0SKamlesh Gurudasani  * Perform the steps necessary to bring this PSC back to a pre-init state.
1200*f6db41e0SKamlesh Gurudasani  * This is performed before a reset domain reset so that the PSC can be
1201*f6db41e0SKamlesh Gurudasani  * re-initialized after the reset is complete.
1202*f6db41e0SKamlesh Gurudasani  */
psc_uninit(struct ti_device * dev)1203*f6db41e0SKamlesh Gurudasani static void psc_uninit(struct ti_device *dev)
1204*f6db41e0SKamlesh Gurudasani {
1205*f6db41e0SKamlesh Gurudasani 	const struct ti_psc_drv_data *psc;
1206*f6db41e0SKamlesh Gurudasani 	struct ti_device *curr_dev;
1207*f6db41e0SKamlesh Gurudasani 	struct ti_device **last_dev;
1208*f6db41e0SKamlesh Gurudasani 
1209*f6db41e0SKamlesh Gurudasani 	psc = ti_to_psc_drv_data(ti_get_drv_data(dev));
1210*f6db41e0SKamlesh Gurudasani 
1211*f6db41e0SKamlesh Gurudasani 	psc_uninitialize_modules(dev);
1212*f6db41e0SKamlesh Gurudasani 	psc_uninitialize_pds(dev);
1213*f6db41e0SKamlesh Gurudasani 
1214*f6db41e0SKamlesh Gurudasani 	/* Remove from list of uninitialized PSCs */
1215*f6db41e0SKamlesh Gurudasani 	curr_dev = psc_devs;
1216*f6db41e0SKamlesh Gurudasani 	last_dev = &psc_devs;
1217*f6db41e0SKamlesh Gurudasani 	while ((curr_dev != NULL) && (curr_dev != dev)) {
1218*f6db41e0SKamlesh Gurudasani 		const struct ti_psc_drv_data *curr_psc;
1219*f6db41e0SKamlesh Gurudasani 
1220*f6db41e0SKamlesh Gurudasani 		curr_psc = ti_to_psc_drv_data(ti_get_drv_data(curr_dev));
1221*f6db41e0SKamlesh Gurudasani 		curr_dev = curr_psc->data->next;
1222*f6db41e0SKamlesh Gurudasani 		last_dev = &curr_psc->data->next;
1223*f6db41e0SKamlesh Gurudasani 	}
1224*f6db41e0SKamlesh Gurudasani 	if (curr_dev == dev) {
1225*f6db41e0SKamlesh Gurudasani 		*last_dev = psc->data->next;
1226*f6db41e0SKamlesh Gurudasani 		psc->data->next = NULL;
1227*f6db41e0SKamlesh Gurudasani 	}
1228*f6db41e0SKamlesh Gurudasani }
1229*f6db41e0SKamlesh Gurudasani 
1230*f6db41e0SKamlesh Gurudasani const struct ti_drv psc_drv = {
1231*f6db41e0SKamlesh Gurudasani 	.pre_init	= psc_pre_init,
1232*f6db41e0SKamlesh Gurudasani 	.post_init	= psc_post_init,
1233*f6db41e0SKamlesh Gurudasani 	.uninit		= psc_uninit,
1234*f6db41e0SKamlesh Gurudasani };
1235