Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.5.6.
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * AM33XX PRM functions
  4 *
  5 * Copyright (C) 2011-2012 Texas Instruments Incorporated - https://www.ti.com/
  6 */
  7
  8#include <linux/kernel.h>
  9#include <linux/types.h>
 10#include <linux/errno.h>
 11#include <linux/err.h>
 12#include <linux/io.h>
 13#include <linux/reboot.h>
 14
 15#include "powerdomain.h"
 16#include "prm33xx.h"
 17#include "prm-regbits-33xx.h"
 18
 19/* Read a register in a PRM instance */
 20static u32 am33xx_prm_read_reg(s16 inst, u16 idx)
 21{
 22	return readl_relaxed(prm_base.va + inst + idx);
 23}
 24
 25/* Write into a register in a PRM instance */
 26static void am33xx_prm_write_reg(u32 val, s16 inst, u16 idx)
 27{
 28	writel_relaxed(val, prm_base.va + inst + idx);
 29}
 30
 31/* Read-modify-write a register in PRM. Caller must lock */
 32static u32 am33xx_prm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx)
 33{
 34	u32 v;
 35
 36	v = am33xx_prm_read_reg(inst, idx);
 37	v &= ~mask;
 38	v |= bits;
 39	am33xx_prm_write_reg(v, inst, idx);
 40
 41	return v;
 42}
 43
 44/**
 45 * am33xx_prm_is_hardreset_asserted - read the HW reset line state of
 46 * submodules contained in the hwmod module
 47 * @shift: register bit shift corresponding to the reset line to check
 48 * @part: PRM partition, ignored for AM33xx
 49 * @inst: CM instance register offset (*_INST macro)
 50 * @rstctrl_offs: RM_RSTCTRL register address offset for this module
 51 *
 52 * Returns 1 if the (sub)module hardreset line is currently asserted,
 53 * 0 if the (sub)module hardreset line is not currently asserted, or
 54 * -EINVAL upon parameter error.
 55 */
 56static int am33xx_prm_is_hardreset_asserted(u8 shift, u8 part, s16 inst,
 57					    u16 rstctrl_offs)
 58{
 59	u32 v;
 60
 61	v = am33xx_prm_read_reg(inst, rstctrl_offs);
 62	v &= 1 << shift;
 63	v >>= shift;
 64
 65	return v;
 66}
 67
 68/**
 69 * am33xx_prm_assert_hardreset - assert the HW reset line of a submodule
 70 * @shift: register bit shift corresponding to the reset line to assert
 71 * @part: CM partition, ignored for AM33xx
 72 * @inst: CM instance register offset (*_INST macro)
 73 * @rstctrl_reg: RM_RSTCTRL register address for this module
 74 *
 75 * Some IPs like dsp, ipu or iva contain processors that require an HW
 76 * reset line to be asserted / deasserted in order to fully enable the
 77 * IP.  These modules may have multiple hard-reset lines that reset
 78 * different 'submodules' inside the IP block.  This function will
 79 * place the submodule into reset.  Returns 0 upon success or -EINVAL
 80 * upon an argument error.
 81 */
 82static int am33xx_prm_assert_hardreset(u8 shift, u8 part, s16 inst,
 83				       u16 rstctrl_offs)
 84{
 85	u32 mask = 1 << shift;
 86
 87	am33xx_prm_rmw_reg_bits(mask, mask, inst, rstctrl_offs);
 88
 89	return 0;
 90}
 91
 92/**
 93 * am33xx_prm_deassert_hardreset - deassert a submodule hardreset line and
 94 * wait
 95 * @shift: register bit shift corresponding to the reset line to deassert
 96 * @st_shift: reset status register bit shift corresponding to the reset line
 97 * @part: PRM partition, not used for AM33xx
 98 * @inst: CM instance register offset (*_INST macro)
 99 * @rstctrl_reg: RM_RSTCTRL register address for this module
100 * @rstst_reg: RM_RSTST register address for this module
101 *
102 * Some IPs like dsp, ipu or iva contain processors that require an HW
103 * reset line to be asserted / deasserted in order to fully enable the
104 * IP.  These modules may have multiple hard-reset lines that reset
105 * different 'submodules' inside the IP block.  This function will
106 * take the submodule out of reset and wait until the PRCM indicates
107 * that the reset has completed before returning.  Returns 0 upon success or
108 * -EINVAL upon an argument error, -EEXIST if the submodule was already out
109 * of reset, or -EBUSY if the submodule did not exit reset promptly.
110 */
111static int am33xx_prm_deassert_hardreset(u8 shift, u8 st_shift, u8 part,
112					 s16 inst, u16 rstctrl_offs,
113					 u16 rstst_offs)
114{
115	int c;
116	u32 mask = 1 << st_shift;
117
118	/* Check the current status to avoid  de-asserting the line twice */
119	if (am33xx_prm_is_hardreset_asserted(shift, 0, inst, rstctrl_offs) == 0)
120		return -EEXIST;
121
122	/* Clear the reset status by writing 1 to the status bit */
123	am33xx_prm_rmw_reg_bits(0xffffffff, mask, inst, rstst_offs);
124
125	/* de-assert the reset control line */
126	mask = 1 << shift;
127
128	am33xx_prm_rmw_reg_bits(mask, 0, inst, rstctrl_offs);
129
130	/* wait the status to be set */
131	omap_test_timeout(am33xx_prm_is_hardreset_asserted(st_shift, 0, inst,
132							   rstst_offs),
133			  MAX_MODULE_HARDRESET_WAIT, c);
134
135	return (c == MAX_MODULE_HARDRESET_WAIT) ? -EBUSY : 0;
136}
137
138static int am33xx_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst)
139{
140	am33xx_prm_rmw_reg_bits(OMAP_POWERSTATE_MASK,
141				(pwrst << OMAP_POWERSTATE_SHIFT),
142				pwrdm->prcm_offs, pwrdm->pwrstctrl_offs);
143	return 0;
144}
145
146static int am33xx_pwrdm_read_next_pwrst(struct powerdomain *pwrdm)
147{
148	u32 v;
149
150	v = am33xx_prm_read_reg(pwrdm->prcm_offs,  pwrdm->pwrstctrl_offs);
151	v &= OMAP_POWERSTATE_MASK;
152	v >>= OMAP_POWERSTATE_SHIFT;
153
154	return v;
155}
156
157static int am33xx_pwrdm_read_pwrst(struct powerdomain *pwrdm)
158{
159	u32 v;
160
161	v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs);
162	v &= OMAP_POWERSTATEST_MASK;
163	v >>= OMAP_POWERSTATEST_SHIFT;
164
165	return v;
166}
167
168static int am33xx_pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm)
169{
170	am33xx_prm_rmw_reg_bits(AM33XX_LOWPOWERSTATECHANGE_MASK,
171				(1 << AM33XX_LOWPOWERSTATECHANGE_SHIFT),
172				pwrdm->prcm_offs, pwrdm->pwrstctrl_offs);
173	return 0;
174}
175
176static int am33xx_pwrdm_clear_all_prev_pwrst(struct powerdomain *pwrdm)
177{
178	am33xx_prm_rmw_reg_bits(AM33XX_LASTPOWERSTATEENTERED_MASK,
179				AM33XX_LASTPOWERSTATEENTERED_MASK,
180				pwrdm->prcm_offs, pwrdm->pwrstst_offs);
181	return 0;
182}
183
184static int am33xx_pwrdm_set_logic_retst(struct powerdomain *pwrdm, u8 pwrst)
185{
186	u32 m;
187
188	m = pwrdm->logicretstate_mask;
189	if (!m)
190		return -EINVAL;
191
192	am33xx_prm_rmw_reg_bits(m, (pwrst << __ffs(m)),
193				pwrdm->prcm_offs, pwrdm->pwrstctrl_offs);
194
195	return 0;
196}
197
198static int am33xx_pwrdm_read_logic_pwrst(struct powerdomain *pwrdm)
199{
200	u32 v;
201
202	v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs);
203	v &= AM33XX_LOGICSTATEST_MASK;
204	v >>= AM33XX_LOGICSTATEST_SHIFT;
205
206	return v;
207}
208
209static int am33xx_pwrdm_read_logic_retst(struct powerdomain *pwrdm)
210{
211	u32 v, m;
212
213	m = pwrdm->logicretstate_mask;
214	if (!m)
215		return -EINVAL;
216
217	v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstctrl_offs);
218	v &= m;
219	v >>= __ffs(m);
220
221	return v;
222}
223
224static int am33xx_pwrdm_set_mem_onst(struct powerdomain *pwrdm, u8 bank,
225		u8 pwrst)
226{
227	u32 m;
228
229	m = pwrdm->mem_on_mask[bank];
230	if (!m)
231		return -EINVAL;
232
233	am33xx_prm_rmw_reg_bits(m, (pwrst << __ffs(m)),
234				pwrdm->prcm_offs, pwrdm->pwrstctrl_offs);
235
236	return 0;
237}
238
239static int am33xx_pwrdm_set_mem_retst(struct powerdomain *pwrdm, u8 bank,
240					u8 pwrst)
241{
242	u32 m;
243
244	m = pwrdm->mem_ret_mask[bank];
245	if (!m)
246		return -EINVAL;
247
248	am33xx_prm_rmw_reg_bits(m, (pwrst << __ffs(m)),
249				pwrdm->prcm_offs, pwrdm->pwrstctrl_offs);
250
251	return 0;
252}
253
254static int am33xx_pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
255{
256	u32 m, v;
257
258	m = pwrdm->mem_pwrst_mask[bank];
259	if (!m)
260		return -EINVAL;
261
262	v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs);
263	v &= m;
264	v >>= __ffs(m);
265
266	return v;
267}
268
269static int am33xx_pwrdm_read_mem_retst(struct powerdomain *pwrdm, u8 bank)
270{
271	u32 m, v;
272
273	m = pwrdm->mem_retst_mask[bank];
274	if (!m)
275		return -EINVAL;
276
277	v = am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstctrl_offs);
278	v &= m;
279	v >>= __ffs(m);
280
281	return v;
282}
283
284static int am33xx_pwrdm_wait_transition(struct powerdomain *pwrdm)
285{
286	u32 c = 0;
287
288	/*
289	 * REVISIT: pwrdm_wait_transition() may be better implemented
290	 * via a callback and a periodic timer check -- how long do we expect
291	 * powerdomain transitions to take?
292	 */
293
294	/* XXX Is this udelay() value meaningful? */
295	while ((am33xx_prm_read_reg(pwrdm->prcm_offs, pwrdm->pwrstst_offs)
296			& OMAP_INTRANSITION_MASK) &&
297			(c++ < PWRDM_TRANSITION_BAILOUT))
298		udelay(1);
299
300	if (c > PWRDM_TRANSITION_BAILOUT) {
301		pr_err("powerdomain: %s: waited too long to complete transition\n",
302		       pwrdm->name);
303		return -EAGAIN;
304	}
305
306	pr_debug("powerdomain: completed transition in %d loops\n", c);
307
308	return 0;
309}
310
311static int am33xx_check_vcvp(void)
312{
313	/* No VC/VP on am33xx devices */
314	return 0;
315}
316
317/**
318 * am33xx_prm_global_warm_sw_reset - reboot the device via warm reset
319 *
320 * Immediately reboots the device through warm reset.
321 */
322static void am33xx_prm_global_sw_reset(void)
323{
324	/*
325	 * Historically AM33xx performed warm reset for all requested reboot_mode.
326	 * Keep this behaviour unchanged for all except newly added REBOOT_COLD.
327	 */
328	u32 mask = AM33XX_RST_GLOBAL_WARM_SW_MASK;
329
330	if (prm_reboot_mode == REBOOT_COLD)
331		mask = AM33XX_RST_GLOBAL_COLD_SW_MASK;
332
333	am33xx_prm_rmw_reg_bits(mask,
334				mask,
335				AM33XX_PRM_DEVICE_MOD,
336				AM33XX_PRM_RSTCTRL_OFFSET);
337
338	/* OCP barrier */
339	(void)am33xx_prm_read_reg(AM33XX_PRM_DEVICE_MOD,
340				  AM33XX_PRM_RSTCTRL_OFFSET);
341}
342
343static void am33xx_pwrdm_save_context(struct powerdomain *pwrdm)
344{
345	pwrdm->context = am33xx_prm_read_reg(pwrdm->prcm_offs,
346						pwrdm->pwrstctrl_offs);
347	/*
348	 * Do not save LOWPOWERSTATECHANGE, writing a 1 indicates a request,
349	 * reading back a 1 indicates a request in progress.
350	 */
351	pwrdm->context &= ~AM33XX_LOWPOWERSTATECHANGE_MASK;
352}
353
354static void am33xx_pwrdm_restore_context(struct powerdomain *pwrdm)
355{
356	int st, ctrl;
357
358	st = am33xx_prm_read_reg(pwrdm->prcm_offs,
359				 pwrdm->pwrstst_offs);
360
361	am33xx_prm_write_reg(pwrdm->context, pwrdm->prcm_offs,
362			     pwrdm->pwrstctrl_offs);
363
364	/* Make sure we only wait for a transition if there is one */
365	st &= OMAP_POWERSTATEST_MASK;
366	ctrl = OMAP_POWERSTATEST_MASK & pwrdm->context;
367
368	if (st != ctrl)
369		am33xx_pwrdm_wait_transition(pwrdm);
370}
371
372struct pwrdm_ops am33xx_pwrdm_operations = {
373	.pwrdm_set_next_pwrst		= am33xx_pwrdm_set_next_pwrst,
374	.pwrdm_read_next_pwrst		= am33xx_pwrdm_read_next_pwrst,
375	.pwrdm_read_pwrst		= am33xx_pwrdm_read_pwrst,
376	.pwrdm_set_logic_retst		= am33xx_pwrdm_set_logic_retst,
377	.pwrdm_read_logic_pwrst		= am33xx_pwrdm_read_logic_pwrst,
378	.pwrdm_read_logic_retst		= am33xx_pwrdm_read_logic_retst,
379	.pwrdm_clear_all_prev_pwrst	= am33xx_pwrdm_clear_all_prev_pwrst,
380	.pwrdm_set_lowpwrstchange	= am33xx_pwrdm_set_lowpwrstchange,
381	.pwrdm_read_mem_pwrst		= am33xx_pwrdm_read_mem_pwrst,
382	.pwrdm_read_mem_retst		= am33xx_pwrdm_read_mem_retst,
383	.pwrdm_set_mem_onst		= am33xx_pwrdm_set_mem_onst,
384	.pwrdm_set_mem_retst		= am33xx_pwrdm_set_mem_retst,
385	.pwrdm_wait_transition		= am33xx_pwrdm_wait_transition,
386	.pwrdm_has_voltdm		= am33xx_check_vcvp,
387	.pwrdm_save_context		= am33xx_pwrdm_save_context,
388	.pwrdm_restore_context		= am33xx_pwrdm_restore_context,
389};
390
391static struct prm_ll_data am33xx_prm_ll_data = {
392	.assert_hardreset		= am33xx_prm_assert_hardreset,
393	.deassert_hardreset		= am33xx_prm_deassert_hardreset,
394	.is_hardreset_asserted		= am33xx_prm_is_hardreset_asserted,
395	.reset_system			= am33xx_prm_global_sw_reset,
396};
397
398int __init am33xx_prm_init(const struct omap_prcm_init_data *data)
399{
400	return prm_register(&am33xx_prm_ll_data);
401}
402
403static void __exit am33xx_prm_exit(void)
404{
405	prm_unregister(&am33xx_prm_ll_data);
406}
407__exitcall(am33xx_prm_exit);