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