pm24xx.c 9.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
/*
 * OMAP2 Power Management Routines
 *
 * Copyright (C) 2005 Texas Instruments, Inc.
 * Copyright (C) 2006-2008 Nokia Corporation
 *
 * Written by:
 * Richard Woodruff <r-woodruff2@ti.com>
 * Tony Lindgren
 * Juha Yrjola
 * Amit Kucheria <amit.kucheria@nokia.com>
 * Igor Stoppa <igor.stoppa@nokia.com>
 *
 * Based on pm.c for omap1
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

#include <linux/suspend.h>
#include <linux/sched.h>
#include <linux/proc_fs.h>
#include <linux/interrupt.h>
#include <linux/sysfs.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/irq.h>
#include <linux/time.h>
#include <linux/gpio.h>

#include <asm/mach/time.h>
#include <asm/mach/irq.h>
#include <asm/mach-types.h>

37 38 39 40
#include <plat/clock.h>
#include <plat/sram.h>
#include <plat/dma.h>
#include <plat/board.h>
41

42 43
#include <mach/irqs.h>

44
#include "common.h"
45
#include "prm2xxx_3xxx.h"
46
#include "prm-regbits-24xx.h"
47
#include "cm2xxx_3xxx.h"
48 49 50
#include "cm-regbits-24xx.h"
#include "sdrc.h"
#include "pm.h"
51
#include "control.h"
52
#include "powerdomain.h"
53
#include "clockdomain.h"
54 55 56 57 58

static void (*omap2_sram_idle)(void);
static void (*omap2_sram_suspend)(u32 dllctrl, void __iomem *sdrc_dlla_ctrl,
				  void __iomem *sdrc_power);

59 60
static struct powerdomain *mpu_pwrdm, *core_pwrdm;
static struct clockdomain *dsp_clkdm, *mpu_clkdm, *wkup_clkdm, *gfx_clkdm;
61 62 63 64 65 66 67

static struct clk *osc_ck, *emul_ck;

static int omap2_fclks_active(void)
{
	u32 f1, f2;

68 69
	f1 = omap2_cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
	f2 = omap2_cm_read_mod_reg(CORE_MOD, OMAP24XX_CM_FCLKEN2);
70

71
	return (f1 | f2) ? 1 : 0;
72 73
}

74
static int omap2_enter_full_retention(void)
75 76 77 78 79 80 81 82 83 84 85 86
{
	u32 l;

	/* There is 1 reference hold for all children of the oscillator
	 * clock, the following will remove it. If no one else uses the
	 * oscillator itself it will be disabled if/when we enter retention
	 * mode.
	 */
	clk_disable(osc_ck);

	/* Clear old wake-up events */
	/* REVISIT: These write to reserved bits? */
87 88 89
	omap2_prm_write_mod_reg(0xffffffff, CORE_MOD, PM_WKST1);
	omap2_prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP24XX_PM_WKST2);
	omap2_prm_write_mod_reg(0xffffffff, WKUP_MOD, PM_WKST);
90 91 92 93 94 95 96 97 98 99 100 101

	/*
	 * Set MPU powerdomain's next power state to RETENTION;
	 * preserve logic state during retention
	 */
	pwrdm_set_logic_retst(mpu_pwrdm, PWRDM_POWER_RET);
	pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_RET);

	/* Workaround to kill USB */
	l = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0) | OMAP24XX_USBSTANDBYCTRL;
	omap_ctrl_writel(l, OMAP2_CONTROL_DEVCONF0);

102
	omap2_gpio_prepare_for_idle(0);
103 104 105

	/* One last check for pending IRQs to avoid extra latency due
	 * to sleeping unnecessarily. */
106
	if (omap_irq_pending())
107 108 109 110 111 112 113
		goto no_sleep;

	/* Jump to SRAM suspend code */
	omap2_sram_suspend(sdrc_read_reg(SDRC_DLLA_CTRL),
			   OMAP_SDRC_REGADDR(SDRC_DLLA_CTRL),
			   OMAP_SDRC_REGADDR(SDRC_POWER));

114
no_sleep:
115
	omap2_gpio_resume_after_idle();
116 117 118 119

	clk_enable(osc_ck);

	/* clear CORE wake-up events */
120 121
	omap2_prm_write_mod_reg(0xffffffff, CORE_MOD, PM_WKST1);
	omap2_prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP24XX_PM_WKST2);
122 123

	/* wakeup domain events - bit 1: GPT1, bit5 GPIO */
124
	omap2_prm_clear_mod_reg_bits(0x4 | 0x1, WKUP_MOD, PM_WKST);
125 126

	/* MPU domain wake events */
127
	l = omap2_prm_read_mod_reg(OCP_MOD, OMAP2_PRCM_IRQSTATUS_MPU_OFFSET);
128
	if (l & 0x01)
129
		omap2_prm_write_mod_reg(0x01, OCP_MOD,
130 131
				  OMAP2_PRCM_IRQSTATUS_MPU_OFFSET);
	if (l & 0x20)
132
		omap2_prm_write_mod_reg(0x20, OCP_MOD,
133 134 135
				  OMAP2_PRCM_IRQSTATUS_MPU_OFFSET);

	/* Mask future PRCM-to-MPU interrupts */
136
	omap2_prm_write_mod_reg(0x0, OCP_MOD, OMAP2_PRCM_IRQSTATUS_MPU_OFFSET);
137 138

	return 0;
139 140 141 142 143 144
}

static int omap2_i2c_active(void)
{
	u32 l;

145
	l = omap2_cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
146
	return l & (OMAP2420_EN_I2C2_MASK | OMAP2420_EN_I2C1_MASK);
147 148 149 150 151 152 153 154 155
}

static int sti_console_enabled;

static int omap2_allow_mpu_retention(void)
{
	u32 l;

	/* Check for MMC, UART2, UART1, McSPI2, McSPI1 and DSS1. */
156
	l = omap2_cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
157 158 159
	if (l & (OMAP2420_EN_MMC_MASK | OMAP24XX_EN_UART2_MASK |
		 OMAP24XX_EN_UART1_MASK | OMAP24XX_EN_MCSPI2_MASK |
		 OMAP24XX_EN_MCSPI1_MASK | OMAP24XX_EN_DSS1_MASK))
160 161
		return 0;
	/* Check for UART3. */
162
	l = omap2_cm_read_mod_reg(CORE_MOD, OMAP24XX_CM_FCLKEN2);
163
	if (l & OMAP24XX_EN_UART3_MASK)
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
		return 0;
	if (sti_console_enabled)
		return 0;

	return 1;
}

static void omap2_enter_mpu_retention(void)
{
	int only_idle = 0;

	/* Putting MPU into the WFI state while a transfer is active
	 * seems to cause the I2C block to timeout. Why? Good question. */
	if (omap2_i2c_active())
		return;

	/* The peripherals seem not to be able to wake up the MPU when
	 * it is in retention mode. */
	if (omap2_allow_mpu_retention()) {
		/* REVISIT: These write to reserved bits? */
184 185 186
		omap2_prm_write_mod_reg(0xffffffff, CORE_MOD, PM_WKST1);
		omap2_prm_write_mod_reg(0xffffffff, CORE_MOD, OMAP24XX_PM_WKST2);
		omap2_prm_write_mod_reg(0xffffffff, WKUP_MOD, PM_WKST);
187 188

		/* Try to enter MPU retention */
189
		omap2_prm_write_mod_reg((0x01 << OMAP_POWERSTATE_SHIFT) |
190
				  OMAP_LOGICRETSTATE_MASK,
191
				  MPU_MOD, OMAP2_PM_PWSTCTRL);
192 193 194
	} else {
		/* Block MPU retention */

195
		omap2_prm_write_mod_reg(OMAP_LOGICRETSTATE_MASK, MPU_MOD,
196
						 OMAP2_PM_PWSTCTRL);
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
		only_idle = 1;
	}

	omap2_sram_idle();
}

static int omap2_can_sleep(void)
{
	if (omap2_fclks_active())
		return 0;
	if (osc_ck->usecount > 1)
		return 0;
	if (omap_dma_running())
		return 0;

	return 1;
}

static void omap2_pm_idle(void)
{
	local_fiq_disable();

	if (!omap2_can_sleep()) {
220
		if (omap_irq_pending())
221 222 223 224 225
			goto out;
		omap2_enter_mpu_retention();
		goto out;
	}

226
	if (omap_irq_pending())
227 228 229 230 231 232 233 234 235 236 237 238 239
		goto out;

	omap2_enter_full_retention();

out:
	local_fiq_enable();
}

static void __init prcm_setup_regs(void)
{
	int i, num_mem_banks;
	struct powerdomain *pwrdm;

240 241 242 243
	/*
	 * Enable autoidle
	 * XXX This should be handled by hwmod code or PRCM init code
	 */
244
	omap2_prm_write_mod_reg(OMAP24XX_AUTOIDLE_MASK, OCP_MOD,
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
			  OMAP2_PRCM_SYSCONFIG_OFFSET);

	/*
	 * Set CORE powerdomain memory banks to retain their contents
	 * during RETENTION
	 */
	num_mem_banks = pwrdm_get_mem_bank_count(core_pwrdm);
	for (i = 0; i < num_mem_banks; i++)
		pwrdm_set_mem_retst(core_pwrdm, i, PWRDM_POWER_RET);

	/* Set CORE powerdomain's next power state to RETENTION */
	pwrdm_set_next_pwrst(core_pwrdm, PWRDM_POWER_RET);

	/*
	 * Set MPU powerdomain's next power state to RETENTION;
	 * preserve logic state during retention
	 */
	pwrdm_set_logic_retst(mpu_pwrdm, PWRDM_POWER_RET);
	pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_RET);

	/* Force-power down DSP, GFX powerdomains */

	pwrdm = clkdm_get_pwrdm(dsp_clkdm);
	pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF);
269
	clkdm_sleep(dsp_clkdm);
270 271 272

	pwrdm = clkdm_get_pwrdm(gfx_clkdm);
	pwrdm_set_next_pwrst(pwrdm, PWRDM_POWER_OFF);
273
	clkdm_sleep(gfx_clkdm);
274

275
	/* Enable hardware-supervised idle for all clkdms */
276
	clkdm_for_each(omap_pm_clkdms_setup, NULL);
277
	clkdm_add_wkdep(mpu_clkdm, wkup_clkdm);
278

279 280 281 282
#ifdef CONFIG_SUSPEND
	omap_pm_suspend = omap2_enter_full_retention;
#endif

283 284
	/* REVISIT: Configure number of 32 kHz clock cycles for sys_clk
	 * stabilisation */
285 286
	omap2_prm_write_mod_reg(15 << OMAP_SETUP_TIME_SHIFT, OMAP24XX_GR_MOD,
				OMAP2_PRCM_CLKSSETUP_OFFSET);
287 288

	/* Configure automatic voltage transition */
289 290 291 292 293 294 295 296
	omap2_prm_write_mod_reg(2 << OMAP_SETUP_TIME_SHIFT, OMAP24XX_GR_MOD,
				OMAP2_PRCM_VOLTSETUP_OFFSET);
	omap2_prm_write_mod_reg(OMAP24XX_AUTO_EXTVOLT_MASK |
				(0x1 << OMAP24XX_SETOFF_LEVEL_SHIFT) |
				OMAP24XX_MEMRETCTRL_MASK |
				(0x1 << OMAP24XX_SETRET_LEVEL_SHIFT) |
				(0x0 << OMAP24XX_VOLT_LEVEL_SHIFT),
				OMAP24XX_GR_MOD, OMAP2_PRCM_VOLTCTRL_OFFSET);
297 298

	/* Enable wake-up events */
299 300
	omap2_prm_write_mod_reg(OMAP24XX_EN_GPIOS_MASK | OMAP24XX_EN_GPT1_MASK,
				WKUP_MOD, PM_WKEN);
301 302
}

303
static int __init omap2_pm_init(void)
304 305 306 307 308 309 310
{
	u32 l;

	if (!cpu_is_omap24xx())
		return -ENODEV;

	printk(KERN_INFO "Power Management for OMAP2 initializing\n");
311
	l = omap2_prm_read_mod_reg(OCP_MOD, OMAP2_PRCM_REVISION_OFFSET);
312 313
	printk(KERN_INFO "PRCM revision %d.%d\n", (l >> 4) & 0x0f, l & 0x0f);

314
	/* Look up important powerdomains */
315 316 317 318 319 320 321 322 323

	mpu_pwrdm = pwrdm_lookup("mpu_pwrdm");
	if (!mpu_pwrdm)
		pr_err("PM: mpu_pwrdm not found\n");

	core_pwrdm = pwrdm_lookup("core_pwrdm");
	if (!core_pwrdm)
		pr_err("PM: core_pwrdm not found\n");

324 325 326 327 328 329 330 331 332 333
	/* Look up important clockdomains */

	mpu_clkdm = clkdm_lookup("mpu_clkdm");
	if (!mpu_clkdm)
		pr_err("PM: mpu_clkdm not found\n");

	wkup_clkdm = clkdm_lookup("wkup_clkdm");
	if (!wkup_clkdm)
		pr_err("PM: wkup_clkdm not found\n");

334 335
	dsp_clkdm = clkdm_lookup("dsp_clkdm");
	if (!dsp_clkdm)
336
		pr_err("PM: dsp_clkdm not found\n");
337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382

	gfx_clkdm = clkdm_lookup("gfx_clkdm");
	if (!gfx_clkdm)
		pr_err("PM: gfx_clkdm not found\n");


	osc_ck = clk_get(NULL, "osc_ck");
	if (IS_ERR(osc_ck)) {
		printk(KERN_ERR "could not get osc_ck\n");
		return -ENODEV;
	}

	if (cpu_is_omap242x()) {
		emul_ck = clk_get(NULL, "emul_ck");
		if (IS_ERR(emul_ck)) {
			printk(KERN_ERR "could not get emul_ck\n");
			clk_put(osc_ck);
			return -ENODEV;
		}
	}

	prcm_setup_regs();

	/* Hack to prevent MPU retention when STI console is enabled. */
	{
		const struct omap_sti_console_config *sti;

		sti = omap_get_config(OMAP_TAG_STI_CONSOLE,
				      struct omap_sti_console_config);
		if (sti != NULL && sti->enable)
			sti_console_enabled = 1;
	}

	/*
	 * We copy the assembler sleep/wakeup routines to SRAM.
	 * These routines need to be in SRAM as that's the only
	 * memory the MPU can see when it wakes up.
	 */
	if (cpu_is_omap24xx()) {
		omap2_sram_idle = omap_sram_push(omap24xx_idle_loop_suspend,
						 omap24xx_idle_loop_suspend_sz);

		omap2_sram_suspend = omap_sram_push(omap24xx_cpu_suspend,
						    omap24xx_cpu_suspend_sz);
	}

383
	arm_pm_idle = omap2_pm_idle;
384 385 386 387 388

	return 0;
}

late_initcall(omap2_pm_init);