1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * AM33XX CM functions
4  *
5  * Copyright (C) 2011-2012 Texas Instruments Incorporated - https://www.ti.com/
6  * Vaibhav Hiremath <hvaibhav@ti.com>
7  *
8  * Reference taken from OMAP4 cminst44xx.c
9  */
10 
11 #include <linux/kernel.h>
12 #include <linux/types.h>
13 #include <linux/errno.h>
14 #include <linux/err.h>
15 #include <linux/io.h>
16 
17 #include "clockdomain.h"
18 #include "cm.h"
19 #include "cm33xx.h"
20 #include "cm-regbits-34xx.h"
21 #include "cm-regbits-33xx.h"
22 #include "prm33xx.h"
23 #if IS_ENABLED(CONFIG_SUSPEND)
24 #include <linux/suspend.h>
25 #endif
26 
27 /*
28  * CLKCTRL_IDLEST_*: possible values for the CM_*_CLKCTRL.IDLEST bitfield:
29  *
30  *   0x0 func:     Module is fully functional, including OCP
31  *   0x1 trans:    Module is performing transition: wakeup, or sleep, or sleep
32  *                 abortion
33  *   0x2 idle:     Module is in Idle mode (only OCP part). It is functional if
34  *                 using separate functional clock
35  *   0x3 disabled: Module is disabled and cannot be accessed
36  *
37  */
38 #define CLKCTRL_IDLEST_FUNCTIONAL		0x0
39 #define CLKCTRL_IDLEST_INTRANSITION		0x1
40 #define CLKCTRL_IDLEST_INTERFACE_IDLE		0x2
41 #define CLKCTRL_IDLEST_DISABLED			0x3
42 
43 /* Private functions */
44 
45 /* Read a register in a CM instance */
46 static inline u32 am33xx_cm_read_reg(u16 inst, u16 idx)
47 {
48 	return readl_relaxed(cm_base.va + inst + idx);
49 }
50 
51 /* Write into a register in a CM */
52 static inline void am33xx_cm_write_reg(u32 val, u16 inst, u16 idx)
53 {
54 	writel_relaxed(val, cm_base.va + inst + idx);
55 }
56 
57 /* Read-modify-write a register in CM */
58 static inline u32 am33xx_cm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx)
59 {
60 	u32 v;
61 
62 	v = am33xx_cm_read_reg(inst, idx);
63 	v &= ~mask;
64 	v |= bits;
65 	am33xx_cm_write_reg(v, inst, idx);
66 
67 	return v;
68 }
69 
70 static inline u32 am33xx_cm_read_reg_bits(u16 inst, s16 idx, u32 mask)
71 {
72 	u32 v;
73 
74 	v = am33xx_cm_read_reg(inst, idx);
75 	v &= mask;
76 	v >>= __ffs(mask);
77 
78 	return v;
79 }
80 
81 /**
82  * _clkctrl_idlest - read a CM_*_CLKCTRL register; mask & shift IDLEST bitfield
83  * @inst: CM instance register offset (*_INST macro)
84  * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
85  *
86  * Return the IDLEST bitfield of a CM_*_CLKCTRL register, shifted down to
87  * bit 0.
88  */
89 static u32 _clkctrl_idlest(u16 inst, u16 clkctrl_offs)
90 {
91 	u32 v = am33xx_cm_read_reg(inst, clkctrl_offs);
92 	v &= AM33XX_IDLEST_MASK;
93 	v >>= AM33XX_IDLEST_SHIFT;
94 	return v;
95 }
96 
97 /**
98  * _is_module_ready - can module registers be accessed without causing an abort?
99  * @inst: CM instance register offset (*_INST macro)
100  * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
101  *
102  * Returns true if the module's CM_*_CLKCTRL.IDLEST bitfield is either
103  * *FUNCTIONAL or *INTERFACE_IDLE; false otherwise.
104  */
105 static bool _is_module_ready(u16 inst, u16 clkctrl_offs)
106 {
107 	u32 v;
108 
109 	v = _clkctrl_idlest(inst, clkctrl_offs);
110 
111 	return (v == CLKCTRL_IDLEST_FUNCTIONAL ||
112 		v == CLKCTRL_IDLEST_INTERFACE_IDLE) ? true : false;
113 }
114 
115 /**
116  * _clktrctrl_write - write @c to a CM_CLKSTCTRL.CLKTRCTRL register bitfield
117  * @c: CLKTRCTRL register bitfield (LSB = bit 0, i.e., unshifted)
118  * @inst: CM instance register offset (*_INST macro)
119  * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
120  *
121  * @c must be the unshifted value for CLKTRCTRL - i.e., this function
122  * will handle the shift itself.
123  */
124 static void _clktrctrl_write(u8 c, u16 inst, u16 cdoffs)
125 {
126 	u32 v;
127 
128 	v = am33xx_cm_read_reg(inst, cdoffs);
129 	v &= ~AM33XX_CLKTRCTRL_MASK;
130 	v |= c << AM33XX_CLKTRCTRL_SHIFT;
131 	am33xx_cm_write_reg(v, inst, cdoffs);
132 }
133 
134 /* Public functions */
135 
136 /**
137  * am33xx_cm_is_clkdm_in_hwsup - is a clockdomain in hwsup idle mode?
138  * @inst: CM instance register offset (*_INST macro)
139  * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
140  *
141  * Returns true if the clockdomain referred to by (@inst, @cdoffs)
142  * is in hardware-supervised idle mode, or 0 otherwise.
143  */
144 static bool am33xx_cm_is_clkdm_in_hwsup(u16 inst, u16 cdoffs)
145 {
146 	u32 v;
147 
148 	v = am33xx_cm_read_reg(inst, cdoffs);
149 	v &= AM33XX_CLKTRCTRL_MASK;
150 	v >>= AM33XX_CLKTRCTRL_SHIFT;
151 
152 	return (v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) ? true : false;
153 }
154 
155 /**
156  * am33xx_cm_clkdm_enable_hwsup - put a clockdomain in hwsup-idle mode
157  * @inst: CM instance register offset (*_INST macro)
158  * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
159  *
160  * Put a clockdomain referred to by (@inst, @cdoffs) into
161  * hardware-supervised idle mode.  No return value.
162  */
163 static void am33xx_cm_clkdm_enable_hwsup(u16 inst, u16 cdoffs)
164 {
165 	_clktrctrl_write(OMAP34XX_CLKSTCTRL_ENABLE_AUTO, inst, cdoffs);
166 }
167 
168 /**
169  * am33xx_cm_clkdm_disable_hwsup - put a clockdomain in swsup-idle mode
170  * @inst: CM instance register offset (*_INST macro)
171  * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
172  *
173  * Put a clockdomain referred to by (@inst, @cdoffs) into
174  * software-supervised idle mode, i.e., controlled manually by the
175  * Linux OMAP clockdomain code.  No return value.
176  */
177 static void am33xx_cm_clkdm_disable_hwsup(u16 inst, u16 cdoffs)
178 {
179 	_clktrctrl_write(OMAP34XX_CLKSTCTRL_DISABLE_AUTO, inst, cdoffs);
180 }
181 
182 /**
183  * am33xx_cm_clkdm_force_sleep - try to put a clockdomain into idle
184  * @inst: CM instance register offset (*_INST macro)
185  * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
186  *
187  * Put a clockdomain referred to by (@inst, @cdoffs) into idle
188  * No return value.
189  */
190 static void am33xx_cm_clkdm_force_sleep(u16 inst, u16 cdoffs)
191 {
192 	_clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_SLEEP, inst, cdoffs);
193 }
194 
195 /**
196  * am33xx_cm_clkdm_force_wakeup - try to take a clockdomain out of idle
197  * @inst: CM instance register offset (*_INST macro)
198  * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
199  *
200  * Take a clockdomain referred to by (@inst, @cdoffs) out of idle,
201  * waking it up.  No return value.
202  */
203 static void am33xx_cm_clkdm_force_wakeup(u16 inst, u16 cdoffs)
204 {
205 	_clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_WAKEUP, inst, cdoffs);
206 }
207 
208 /*
209  *
210  */
211 
212 /**
213  * am33xx_cm_wait_module_ready - wait for a module to be in 'func' state
214  * @part: PRCM partition, ignored for AM33xx
215  * @inst: CM instance register offset (*_INST macro)
216  * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
217  * @bit_shift: bit shift for the register, ignored for AM33xx
218  *
219  * Wait for the module IDLEST to be functional. If the idle state is in any
220  * the non functional state (trans, idle or disabled), module and thus the
221  * sysconfig cannot be accessed and will probably lead to an "imprecise
222  * external abort"
223  */
224 static int am33xx_cm_wait_module_ready(u8 part, s16 inst, u16 clkctrl_offs,
225 				       u8 bit_shift)
226 {
227 	int i = 0;
228 
229 	omap_test_timeout(_is_module_ready(inst, clkctrl_offs),
230 			  MAX_MODULE_READY_TIME, i);
231 
232 	return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY;
233 }
234 
235 /**
236  * am33xx_cm_wait_module_idle - wait for a module to be in 'disabled'
237  * state
238  * @part: CM partition, ignored for AM33xx
239  * @inst: CM instance register offset (*_INST macro)
240  * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
241  * @bit_shift: bit shift for the register, ignored for AM33xx
242  *
243  * Wait for the module IDLEST to be disabled. Some PRCM transition,
244  * like reset assertion or parent clock de-activation must wait the
245  * module to be fully disabled.
246  */
247 static int am33xx_cm_wait_module_idle(u8 part, s16 inst, u16 clkctrl_offs,
248 				      u8 bit_shift)
249 {
250 	int i = 0;
251 
252 	omap_test_timeout((_clkctrl_idlest(inst, clkctrl_offs) ==
253 				CLKCTRL_IDLEST_DISABLED),
254 				MAX_MODULE_READY_TIME, i);
255 
256 	return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY;
257 }
258 
259 /**
260  * am33xx_cm_module_enable - Enable the modulemode inside CLKCTRL
261  * @mode: Module mode (SW or HW)
262  * @part: CM partition, ignored for AM33xx
263  * @inst: CM instance register offset (*_INST macro)
264  * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
265  *
266  * No return value.
267  */
268 static void am33xx_cm_module_enable(u8 mode, u8 part, u16 inst,
269 				    u16 clkctrl_offs)
270 {
271 	u32 v;
272 
273 	v = am33xx_cm_read_reg(inst, clkctrl_offs);
274 	v &= ~AM33XX_MODULEMODE_MASK;
275 	v |= mode << AM33XX_MODULEMODE_SHIFT;
276 	am33xx_cm_write_reg(v, inst, clkctrl_offs);
277 }
278 
279 /**
280  * am33xx_cm_module_disable - Disable the module inside CLKCTRL
281  * @part: CM partition, ignored for AM33xx
282  * @inst: CM instance register offset (*_INST macro)
283  * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
284  *
285  * No return value.
286  */
287 static void am33xx_cm_module_disable(u8 part, u16 inst, u16 clkctrl_offs)
288 {
289 	u32 v;
290 
291 	v = am33xx_cm_read_reg(inst, clkctrl_offs);
292 	v &= ~AM33XX_MODULEMODE_MASK;
293 	am33xx_cm_write_reg(v, inst, clkctrl_offs);
294 }
295 
296 /*
297  * Clockdomain low-level functions
298  */
299 
300 static int am33xx_clkdm_sleep(struct clockdomain *clkdm)
301 {
302 	am33xx_cm_clkdm_force_sleep(clkdm->cm_inst, clkdm->clkdm_offs);
303 	return 0;
304 }
305 
306 static int am33xx_clkdm_wakeup(struct clockdomain *clkdm)
307 {
308 	am33xx_cm_clkdm_force_wakeup(clkdm->cm_inst, clkdm->clkdm_offs);
309 	return 0;
310 }
311 
312 static void am33xx_clkdm_allow_idle(struct clockdomain *clkdm)
313 {
314 	am33xx_cm_clkdm_enable_hwsup(clkdm->cm_inst, clkdm->clkdm_offs);
315 }
316 
317 static void am33xx_clkdm_deny_idle(struct clockdomain *clkdm)
318 {
319 	am33xx_cm_clkdm_disable_hwsup(clkdm->cm_inst, clkdm->clkdm_offs);
320 }
321 
322 static int am33xx_clkdm_clk_enable(struct clockdomain *clkdm)
323 {
324 	if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
325 		return am33xx_clkdm_wakeup(clkdm);
326 
327 	return 0;
328 }
329 
330 static int am33xx_clkdm_clk_disable(struct clockdomain *clkdm)
331 {
332 	bool hwsup = false;
333 
334 #if IS_ENABLED(CONFIG_SUSPEND)
335 	/*
336 	 * In case of standby, Don't put the l4ls clk domain to sleep.
337 	 * Since CM3 PM FW doesn't wake-up/enable the l4ls clk domain
338 	 * upon wake-up, CM3 PM FW fails to wake-up th MPU.
339 	 */
340 	if (pm_suspend_target_state == PM_SUSPEND_STANDBY &&
341 	    (clkdm->flags & CLKDM_STANDBY_FORCE_WAKEUP))
342 		return 0;
343 #endif
344 	hwsup = am33xx_cm_is_clkdm_in_hwsup(clkdm->cm_inst, clkdm->clkdm_offs);
345 	if (!hwsup && (clkdm->flags & CLKDM_CAN_FORCE_SLEEP))
346 		am33xx_clkdm_sleep(clkdm);
347 
348 	return 0;
349 }
350 
351 static u32 am33xx_cm_xlate_clkctrl(u8 part, u16 inst, u16 offset)
352 {
353 	return cm_base.pa + inst + offset;
354 }
355 
356 /**
357  * am33xx_clkdm_save_context - Save the clockdomain transition context
358  * @clkdm: The clockdomain pointer whose context needs to be saved
359  *
360  * Save the clockdomain transition context.
361  */
362 static int am33xx_clkdm_save_context(struct clockdomain *clkdm)
363 {
364 	clkdm->context = am33xx_cm_read_reg_bits(clkdm->cm_inst,
365 						 clkdm->clkdm_offs,
366 						 AM33XX_CLKTRCTRL_MASK);
367 
368 	return 0;
369 }
370 
371 /**
372  * am33xx_clkdm_restore_context - Restore the clockdomain transition context
373  * @clkdm: The clockdomain pointer whose context needs to be restored
374  *
375  * Restore the clockdomain transition context.
376  */
377 static int am33xx_clkdm_restore_context(struct clockdomain *clkdm)
378 {
379 	switch (clkdm->context) {
380 	case OMAP34XX_CLKSTCTRL_DISABLE_AUTO:
381 		am33xx_clkdm_deny_idle(clkdm);
382 		break;
383 	case OMAP34XX_CLKSTCTRL_FORCE_SLEEP:
384 		am33xx_clkdm_sleep(clkdm);
385 		break;
386 	case OMAP34XX_CLKSTCTRL_FORCE_WAKEUP:
387 		am33xx_clkdm_wakeup(clkdm);
388 		break;
389 	case OMAP34XX_CLKSTCTRL_ENABLE_AUTO:
390 		am33xx_clkdm_allow_idle(clkdm);
391 		break;
392 	}
393 	return 0;
394 }
395 
396 struct clkdm_ops am33xx_clkdm_operations = {
397 	.clkdm_sleep		= am33xx_clkdm_sleep,
398 	.clkdm_wakeup		= am33xx_clkdm_wakeup,
399 	.clkdm_allow_idle	= am33xx_clkdm_allow_idle,
400 	.clkdm_deny_idle	= am33xx_clkdm_deny_idle,
401 	.clkdm_clk_enable	= am33xx_clkdm_clk_enable,
402 	.clkdm_clk_disable	= am33xx_clkdm_clk_disable,
403 	.clkdm_save_context	= am33xx_clkdm_save_context,
404 	.clkdm_restore_context	= am33xx_clkdm_restore_context,
405 };
406 
407 static const struct cm_ll_data am33xx_cm_ll_data = {
408 	.wait_module_ready	= &am33xx_cm_wait_module_ready,
409 	.wait_module_idle	= &am33xx_cm_wait_module_idle,
410 	.module_enable		= &am33xx_cm_module_enable,
411 	.module_disable		= &am33xx_cm_module_disable,
412 	.xlate_clkctrl		= &am33xx_cm_xlate_clkctrl,
413 };
414 
415 int __init am33xx_cm_init(const struct omap_prcm_init_data *data)
416 {
417 	return cm_register(&am33xx_cm_ll_data);
418 }
419 
420 static void __exit am33xx_cm_exit(void)
421 {
422 	cm_unregister(&am33xx_cm_ll_data);
423 }
424 __exitcall(am33xx_cm_exit);
425