Linux Audio

Check our new training course

Linux debugging, profiling, tracing and performance analysis training

Mar 24-27, 2025, special US time zones
Register
Loading...
Note: File does not exist in v6.13.7.
  1/*
  2 * OMAP2 Power Management Routines
  3 *
  4 * Copyright (C) 2005 Texas Instruments, Inc.
  5 * Copyright (C) 2006-2008 Nokia Corporation
  6 *
  7 * Written by:
  8 * Richard Woodruff <r-woodruff2@ti.com>
  9 * Tony Lindgren
 10 * Juha Yrjola
 11 * Amit Kucheria <amit.kucheria@nokia.com>
 12 * Igor Stoppa <igor.stoppa@nokia.com>
 13 *
 14 * Based on pm.c for omap1
 15 *
 16 * This program is free software; you can redistribute it and/or modify
 17 * it under the terms of the GNU General Public License version 2 as
 18 * published by the Free Software Foundation.
 19 */
 20
 21#include <linux/suspend.h>
 22#include <linux/sched.h>
 23#include <linux/proc_fs.h>
 24#include <linux/interrupt.h>
 25#include <linux/sysfs.h>
 26#include <linux/module.h>
 27#include <linux/delay.h>
 28#include <linux/clk.h>
 29#include <linux/io.h>
 30#include <linux/irq.h>
 31#include <linux/time.h>
 32#include <linux/gpio.h>
 33#include <linux/console.h>
 34
 35#include <asm/mach/time.h>
 36#include <asm/mach/irq.h>
 37#include <asm/mach-types.h>
 38
 39#include <mach/irqs.h>
 40#include <plat/clock.h>
 41#include <plat/sram.h>
 42#include <plat/dma.h>
 43#include <plat/board.h>
 44
 45#include "prm2xxx_3xxx.h"
 46#include "prm-regbits-24xx.h"
 47#include "cm2xxx_3xxx.h"
 48#include "cm-regbits-24xx.h"
 49#include "sdrc.h"
 50#include "pm.h"
 51#include "control.h"
 52
 53#include "powerdomain.h"
 54#include "clockdomain.h"
 55
 56static int omap2_pm_debug;
 57
 58#ifdef CONFIG_SUSPEND
 59static suspend_state_t suspend_state = PM_SUSPEND_ON;
 60static inline bool is_suspending(void)
 61{
 62	return (suspend_state != PM_SUSPEND_ON);
 63}
 64#else
 65static inline bool is_suspending(void)
 66{
 67	return false;
 68}
 69#endif
 70
 71static void (*omap2_sram_idle)(void);
 72static void (*omap2_sram_suspend)(u32 dllctrl, void __iomem *sdrc_dlla_ctrl,
 73				  void __iomem *sdrc_power);
 74
 75static struct powerdomain *mpu_pwrdm, *core_pwrdm;
 76static struct clockdomain *dsp_clkdm, *mpu_clkdm, *wkup_clkdm, *gfx_clkdm;
 77
 78static struct clk *osc_ck, *emul_ck;
 79
 80static int omap2_fclks_active(void)
 81{
 82	u32 f1, f2;
 83
 84	f1 = omap2_cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
 85	f2 = omap2_cm_read_mod_reg(CORE_MOD, OMAP24XX_CM_FCLKEN2);
 86
 87	/* Ignore UART clocks.  These are handled by UART core (serial.c) */
 88	f1 &= ~(OMAP24XX_EN_UART1_MASK | OMAP24XX_EN_UART2_MASK);
 89	f2 &= ~OMAP24XX_EN_UART3_MASK;
 90
 91	if (f1 | f2)
 92		return 1;
 93	return 0;
 94}
 95
 96static void omap2_enter_full_retention(void)
 97{
 98	u32 l;
 99	struct timespec ts_preidle, ts_postidle, ts_idle;
100
101	/* There is 1 reference hold for all children of the oscillator
102	 * clock, the following will remove it. If no one else uses the
103	 * oscillator itself it will be disabled if/when we enter retention
104	 * mode.
105	 */
106	clk_disable(osc_ck);
107
108	/* Clear old wake-up events */
109	/* REVISIT: These write to reserved bits? */
110	omap2_prm_write_mod_reg(0xffffffff, CORE_MOD, PM_WKST1);
111	omap2_prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP24XX_PM_WKST2);
112	omap2_prm_write_mod_reg(0xffffffff, WKUP_MOD, PM_WKST);
113
114	/*
115	 * Set MPU powerdomain's next power state to RETENTION;
116	 * preserve logic state during retention
117	 */
118	pwrdm_set_logic_retst(mpu_pwrdm, PWRDM_POWER_RET);
119	pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_RET);
120
121	/* Workaround to kill USB */
122	l = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0) | OMAP24XX_USBSTANDBYCTRL;
123	omap_ctrl_writel(l, OMAP2_CONTROL_DEVCONF0);
124
125	omap2_gpio_prepare_for_idle(0);
126
127	if (omap2_pm_debug) {
128		getnstimeofday(&ts_preidle);
129	}
130
131	/* One last check for pending IRQs to avoid extra latency due
132	 * to sleeping unnecessarily. */
133	if (omap_irq_pending())
134		goto no_sleep;
135
136	/* Block console output in case it is on one of the OMAP UARTs */
137	if (!is_suspending())
138		if (!console_trylock())
139			goto no_sleep;
140
141	omap_uart_prepare_idle(0);
142	omap_uart_prepare_idle(1);
143	omap_uart_prepare_idle(2);
144
145	/* Jump to SRAM suspend code */
146	omap2_sram_suspend(sdrc_read_reg(SDRC_DLLA_CTRL),
147			   OMAP_SDRC_REGADDR(SDRC_DLLA_CTRL),
148			   OMAP_SDRC_REGADDR(SDRC_POWER));
149
150	omap_uart_resume_idle(2);
151	omap_uart_resume_idle(1);
152	omap_uart_resume_idle(0);
153
154	if (!is_suspending())
155		console_unlock();
156
157no_sleep:
158	if (omap2_pm_debug) {
159		unsigned long long tmp;
160
161		getnstimeofday(&ts_postidle);
162		ts_idle = timespec_sub(ts_postidle, ts_preidle);
163		tmp = timespec_to_ns(&ts_idle) * NSEC_PER_USEC;
164	}
165	omap2_gpio_resume_after_idle();
166
167	clk_enable(osc_ck);
168
169	/* clear CORE wake-up events */
170	omap2_prm_write_mod_reg(0xffffffff, CORE_MOD, PM_WKST1);
171	omap2_prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP24XX_PM_WKST2);
172
173	/* wakeup domain events - bit 1: GPT1, bit5 GPIO */
174	omap2_prm_clear_mod_reg_bits(0x4 | 0x1, WKUP_MOD, PM_WKST);
175
176	/* MPU domain wake events */
177	l = omap2_prm_read_mod_reg(OCP_MOD, OMAP2_PRCM_IRQSTATUS_MPU_OFFSET);
178	if (l & 0x01)
179		omap2_prm_write_mod_reg(0x01, OCP_MOD,
180				  OMAP2_PRCM_IRQSTATUS_MPU_OFFSET);
181	if (l & 0x20)
182		omap2_prm_write_mod_reg(0x20, OCP_MOD,
183				  OMAP2_PRCM_IRQSTATUS_MPU_OFFSET);
184
185	/* Mask future PRCM-to-MPU interrupts */
186	omap2_prm_write_mod_reg(0x0, OCP_MOD, OMAP2_PRCM_IRQSTATUS_MPU_OFFSET);
187}
188
189static int omap2_i2c_active(void)
190{
191	u32 l;
192
193	l = omap2_cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
194	return l & (OMAP2420_EN_I2C2_MASK | OMAP2420_EN_I2C1_MASK);
195}
196
197static int sti_console_enabled;
198
199static int omap2_allow_mpu_retention(void)
200{
201	u32 l;
202
203	/* Check for MMC, UART2, UART1, McSPI2, McSPI1 and DSS1. */
204	l = omap2_cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
205	if (l & (OMAP2420_EN_MMC_MASK | OMAP24XX_EN_UART2_MASK |
206		 OMAP24XX_EN_UART1_MASK | OMAP24XX_EN_MCSPI2_MASK |
207		 OMAP24XX_EN_MCSPI1_MASK | OMAP24XX_EN_DSS1_MASK))
208		return 0;
209	/* Check for UART3. */
210	l = omap2_cm_read_mod_reg(CORE_MOD, OMAP24XX_CM_FCLKEN2);
211	if (l & OMAP24XX_EN_UART3_MASK)
212		return 0;
213	if (sti_console_enabled)
214		return 0;
215
216	return 1;
217}
218
219static void omap2_enter_mpu_retention(void)
220{
221	int only_idle = 0;
222	struct timespec ts_preidle, ts_postidle, ts_idle;
223
224	/* Putting MPU into the WFI state while a transfer is active
225	 * seems to cause the I2C block to timeout. Why? Good question. */
226	if (omap2_i2c_active())
227		return;
228
229	/* The peripherals seem not to be able to wake up the MPU when
230	 * it is in retention mode. */
231	if (omap2_allow_mpu_retention()) {
232		/* REVISIT: These write to reserved bits? */
233		omap2_prm_write_mod_reg(0xffffffff, CORE_MOD, PM_WKST1);
234		omap2_prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP24XX_PM_WKST2);
235		omap2_prm_write_mod_reg(0xffffffff, WKUP_MOD, PM_WKST);
236
237		/* Try to enter MPU retention */
238		omap2_prm_write_mod_reg((0x01 << OMAP_POWERSTATE_SHIFT) |
239				  OMAP_LOGICRETSTATE_MASK,
240				  MPU_MOD, OMAP2_PM_PWSTCTRL);
241	} else {
242		/* Block MPU retention */
243
244		omap2_prm_write_mod_reg(OMAP_LOGICRETSTATE_MASK, MPU_MOD,
245						 OMAP2_PM_PWSTCTRL);
246		only_idle = 1;
247	}
248
249	if (omap2_pm_debug) {
250		getnstimeofday(&ts_preidle);
251	}
252
253	omap2_sram_idle();
254
255	if (omap2_pm_debug) {
256		unsigned long long tmp;
257
258		getnstimeofday(&ts_postidle);
259		ts_idle = timespec_sub(ts_postidle, ts_preidle);
260		tmp = timespec_to_ns(&ts_idle) * NSEC_PER_USEC;
261	}
262}
263
264static int omap2_can_sleep(void)
265{
266	if (omap2_fclks_active())
267		return 0;
268	if (!omap_uart_can_sleep())
269		return 0;
270	if (osc_ck->usecount > 1)
271		return 0;
272	if (omap_dma_running())
273		return 0;
274
275	return 1;
276}
277
278static void omap2_pm_idle(void)
279{
280	local_irq_disable();
281	local_fiq_disable();
282
283	if (!omap2_can_sleep()) {
284		if (omap_irq_pending())
285			goto out;
286		omap2_enter_mpu_retention();
287		goto out;
288	}
289
290	if (omap_irq_pending())
291		goto out;
292
293	omap2_enter_full_retention();
294
295out:
296	local_fiq_enable();
297	local_irq_enable();
298}
299
300#ifdef CONFIG_SUSPEND
301static int omap2_pm_begin(suspend_state_t state)
302{
303	disable_hlt();
304	suspend_state = state;
305	return 0;
306}
307
308static int omap2_pm_suspend(void)
309{
310	u32 wken_wkup, mir1;
311
312	wken_wkup = omap2_prm_read_mod_reg(WKUP_MOD, PM_WKEN);
313	wken_wkup &= ~OMAP24XX_EN_GPT1_MASK;
314	omap2_prm_write_mod_reg(wken_wkup, WKUP_MOD, PM_WKEN);
315
316	/* Mask GPT1 */
317	mir1 = omap_readl(0x480fe0a4);
318	omap_writel(1 << 5, 0x480fe0ac);
319
320	omap_uart_prepare_suspend();
321	omap2_enter_full_retention();
322
323	omap_writel(mir1, 0x480fe0a4);
324	omap2_prm_write_mod_reg(wken_wkup, WKUP_MOD, PM_WKEN);
325
326	return 0;
327}
328
329static int omap2_pm_enter(suspend_state_t state)
330{
331	int ret = 0;
332
333	switch (state) {
334	case PM_SUSPEND_STANDBY:
335	case PM_SUSPEND_MEM:
336		ret = omap2_pm_suspend();
337		break;
338	default:
339		ret = -EINVAL;
340	}
341
342	return ret;
343}
344
345static void omap2_pm_end(void)
346{
347	suspend_state = PM_SUSPEND_ON;
348	enable_hlt();
349}
350
351static const struct platform_suspend_ops omap_pm_ops = {
352	.begin		= omap2_pm_begin,
353	.enter		= omap2_pm_enter,
354	.end		= omap2_pm_end,
355	.valid		= suspend_valid_only_mem,
356};
357#else
358static const struct platform_suspend_ops __initdata omap_pm_ops;
359#endif /* CONFIG_SUSPEND */
360
361/* XXX This function should be shareable between OMAP2xxx and OMAP3 */
362static int __init clkdms_setup(struct clockdomain *clkdm, void *unused)
363{
364	if (clkdm->flags & CLKDM_CAN_ENABLE_AUTO)
365		clkdm_allow_idle(clkdm);
366	else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP &&
367		 atomic_read(&clkdm->usecount) == 0)
368		clkdm_sleep(clkdm);
369	return 0;
370}
371
372static void __init prcm_setup_regs(void)
373{
374	int i, num_mem_banks;
375	struct powerdomain *pwrdm;
376
377	/*
378	 * Enable autoidle
379	 * XXX This should be handled by hwmod code or PRCM init code
380	 */
381	omap2_prm_write_mod_reg(OMAP24XX_AUTOIDLE_MASK, OCP_MOD,
382			  OMAP2_PRCM_SYSCONFIG_OFFSET);
383
384	/*
385	 * Set CORE powerdomain memory banks to retain their contents
386	 * during RETENTION
387	 */
388	num_mem_banks = pwrdm_get_mem_bank_count(core_pwrdm);
389	for (i = 0; i < num_mem_banks; i++)
390		pwrdm_set_mem_retst(core_pwrdm, i, PWRDM_POWER_RET);
391
392	/* Set CORE powerdomain's next power state to RETENTION */
393	pwrdm_set_next_pwrst(core_pwrdm, PWRDM_POWER_RET);
394
395	/*
396	 * Set MPU powerdomain's next power state to RETENTION;
397	 * preserve logic state during retention
398	 */
399	pwrdm_set_logic_retst(mpu_pwrdm, PWRDM_POWER_RET);
400	pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_RET);
401
402	/* Force-power down DSP, GFX powerdomains */
403
404	pwrdm = clkdm_get_pwrdm(dsp_clkdm);
405	pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF);
406	clkdm_sleep(dsp_clkdm);
407
408	pwrdm = clkdm_get_pwrdm(gfx_clkdm);
409	pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF);
410	clkdm_sleep(gfx_clkdm);
411
412	/* Enable hardware-supervised idle for all clkdms */
413	clkdm_for_each(clkdms_setup, NULL);
414	clkdm_add_wkdep(mpu_clkdm, wkup_clkdm);
415
416	/* REVISIT: Configure number of 32 kHz clock cycles for sys_clk
417	 * stabilisation */
418	omap2_prm_write_mod_reg(15 << OMAP_SETUP_TIME_SHIFT, OMAP24XX_GR_MOD,
419				OMAP2_PRCM_CLKSSETUP_OFFSET);
420
421	/* Configure automatic voltage transition */
422	omap2_prm_write_mod_reg(2 << OMAP_SETUP_TIME_SHIFT, OMAP24XX_GR_MOD,
423				OMAP2_PRCM_VOLTSETUP_OFFSET);
424	omap2_prm_write_mod_reg(OMAP24XX_AUTO_EXTVOLT_MASK |
425				(0x1 << OMAP24XX_SETOFF_LEVEL_SHIFT) |
426				OMAP24XX_MEMRETCTRL_MASK |
427				(0x1 << OMAP24XX_SETRET_LEVEL_SHIFT) |
428				(0x0 << OMAP24XX_VOLT_LEVEL_SHIFT),
429				OMAP24XX_GR_MOD, OMAP2_PRCM_VOLTCTRL_OFFSET);
430
431	/* Enable wake-up events */
432	omap2_prm_write_mod_reg(OMAP24XX_EN_GPIOS_MASK | OMAP24XX_EN_GPT1_MASK,
433				WKUP_MOD, PM_WKEN);
434}
435
436static int __init omap2_pm_init(void)
437{
438	u32 l;
439
440	if (!cpu_is_omap24xx())
441		return -ENODEV;
442
443	printk(KERN_INFO "Power Management for OMAP2 initializing\n");
444	l = omap2_prm_read_mod_reg(OCP_MOD, OMAP2_PRCM_REVISION_OFFSET);
445	printk(KERN_INFO "PRCM revision %d.%d\n", (l >> 4) & 0x0f, l & 0x0f);
446
447	/* Look up important powerdomains */
448
449	mpu_pwrdm = pwrdm_lookup("mpu_pwrdm");
450	if (!mpu_pwrdm)
451		pr_err("PM: mpu_pwrdm not found\n");
452
453	core_pwrdm = pwrdm_lookup("core_pwrdm");
454	if (!core_pwrdm)
455		pr_err("PM: core_pwrdm not found\n");
456
457	/* Look up important clockdomains */
458
459	mpu_clkdm = clkdm_lookup("mpu_clkdm");
460	if (!mpu_clkdm)
461		pr_err("PM: mpu_clkdm not found\n");
462
463	wkup_clkdm = clkdm_lookup("wkup_clkdm");
464	if (!wkup_clkdm)
465		pr_err("PM: wkup_clkdm not found\n");
466
467	dsp_clkdm = clkdm_lookup("dsp_clkdm");
468	if (!dsp_clkdm)
469		pr_err("PM: dsp_clkdm not found\n");
470
471	gfx_clkdm = clkdm_lookup("gfx_clkdm");
472	if (!gfx_clkdm)
473		pr_err("PM: gfx_clkdm not found\n");
474
475
476	osc_ck = clk_get(NULL, "osc_ck");
477	if (IS_ERR(osc_ck)) {
478		printk(KERN_ERR "could not get osc_ck\n");
479		return -ENODEV;
480	}
481
482	if (cpu_is_omap242x()) {
483		emul_ck = clk_get(NULL, "emul_ck");
484		if (IS_ERR(emul_ck)) {
485			printk(KERN_ERR "could not get emul_ck\n");
486			clk_put(osc_ck);
487			return -ENODEV;
488		}
489	}
490
491	prcm_setup_regs();
492
493	/* Hack to prevent MPU retention when STI console is enabled. */
494	{
495		const struct omap_sti_console_config *sti;
496
497		sti = omap_get_config(OMAP_TAG_STI_CONSOLE,
498				      struct omap_sti_console_config);
499		if (sti != NULL && sti->enable)
500			sti_console_enabled = 1;
501	}
502
503	/*
504	 * We copy the assembler sleep/wakeup routines to SRAM.
505	 * These routines need to be in SRAM as that's the only
506	 * memory the MPU can see when it wakes up.
507	 */
508	if (cpu_is_omap24xx()) {
509		omap2_sram_idle = omap_sram_push(omap24xx_idle_loop_suspend,
510						 omap24xx_idle_loop_suspend_sz);
511
512		omap2_sram_suspend = omap_sram_push(omap24xx_cpu_suspend,
513						    omap24xx_cpu_suspend_sz);
514	}
515
516	suspend_set_ops(&omap_pm_ops);
517	pm_idle = omap2_pm_idle;
518
519	return 0;
520}
521
522late_initcall(omap2_pm_init);