diff options
Diffstat (limited to 'arch/arm/mach-omap2/prm2xxx.c')
| -rw-r--r-- | arch/arm/mach-omap2/prm2xxx.c | 208 | 
1 files changed, 208 insertions, 0 deletions
diff --git a/arch/arm/mach-omap2/prm2xxx.c b/arch/arm/mach-omap2/prm2xxx.c new file mode 100644 index 00000000000..a3a3cca2bcc --- /dev/null +++ b/arch/arm/mach-omap2/prm2xxx.c @@ -0,0 +1,208 @@ +/* + * OMAP2xxx PRM module functions + * + * Copyright (C) 2010-2012 Texas Instruments, Inc. + * Copyright (C) 2010 Nokia Corporation + * BenoƮt Cousson + * Paul Walmsley + * Rajendra Nayak <rnayak@ti.com> + * + * 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/kernel.h> +#include <linux/errno.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/irq.h> + +#include "powerdomain.h" +#include "clockdomain.h" +#include "prm2xxx.h" +#include "cm2xxx_3xxx.h" +#include "prm-regbits-24xx.h" + +/* + * OMAP24xx PM_PWSTCTRL_*.POWERSTATE and PM_PWSTST_*.LASTSTATEENTERED bits - + * these are reversed from the bits used on OMAP3+ + */ +#define OMAP24XX_PWRDM_POWER_ON			0x0 +#define OMAP24XX_PWRDM_POWER_RET		0x1 +#define OMAP24XX_PWRDM_POWER_OFF		0x3 + +/* + * omap2xxx_prm_reset_src_map - map from bits in the PRM_RSTST_WKUP + *   hardware register (which are specific to the OMAP2xxx SoCs) to + *   reset source ID bit shifts (which is an OMAP SoC-independent + *   enumeration) + */ +static struct prm_reset_src_map omap2xxx_prm_reset_src_map[] = { +	{ OMAP_GLOBALCOLD_RST_SHIFT, OMAP_GLOBAL_COLD_RST_SRC_ID_SHIFT }, +	{ OMAP_GLOBALWARM_RST_SHIFT, OMAP_GLOBAL_WARM_RST_SRC_ID_SHIFT }, +	{ OMAP24XX_SECU_VIOL_RST_SHIFT, OMAP_SECU_VIOL_RST_SRC_ID_SHIFT }, +	{ OMAP24XX_MPU_WD_RST_SHIFT, OMAP_MPU_WD_RST_SRC_ID_SHIFT }, +	{ OMAP24XX_SECU_WD_RST_SHIFT, OMAP_SECU_WD_RST_SRC_ID_SHIFT }, +	{ OMAP24XX_EXTWMPU_RST_SHIFT, OMAP_EXTWARM_RST_SRC_ID_SHIFT }, +	{ -1, -1 }, +}; + +/** + * omap2xxx_prm_read_reset_sources - return the last SoC reset source + * + * Return a u32 representing the last reset sources of the SoC.  The + * returned reset source bits are standardized across OMAP SoCs. + */ +static u32 omap2xxx_prm_read_reset_sources(void) +{ +	struct prm_reset_src_map *p; +	u32 r = 0; +	u32 v; + +	v = omap2_prm_read_mod_reg(WKUP_MOD, OMAP2_RM_RSTST); + +	p = omap2xxx_prm_reset_src_map; +	while (p->reg_shift >= 0 && p->std_shift >= 0) { +		if (v & (1 << p->reg_shift)) +			r |= 1 << p->std_shift; +		p++; +	} + +	return r; +} + +/** + * omap2xxx_pwrst_to_common_pwrst - convert OMAP2xxx pwrst to common pwrst + * @omap2xxx_pwrst: OMAP2xxx hardware power state to convert + * + * Return the common power state bits corresponding to the OMAP2xxx + * hardware power state bits @omap2xxx_pwrst, or -EINVAL upon error. + */ +static int omap2xxx_pwrst_to_common_pwrst(u8 omap2xxx_pwrst) +{ +	u8 pwrst; + +	switch (omap2xxx_pwrst) { +	case OMAP24XX_PWRDM_POWER_OFF: +		pwrst = PWRDM_POWER_OFF; +		break; +	case OMAP24XX_PWRDM_POWER_RET: +		pwrst = PWRDM_POWER_RET; +		break; +	case OMAP24XX_PWRDM_POWER_ON: +		pwrst = PWRDM_POWER_ON; +		break; +	default: +		return -EINVAL; +	} + +	return pwrst; +} + +/** + * omap2xxx_prm_dpll_reset - use DPLL reset to reboot the OMAP SoC + * + * Set the DPLL reset bit, which should reboot the SoC.  This is the + * recommended way to restart the SoC.  No return value. + */ +void omap2xxx_prm_dpll_reset(void) +{ +	omap2_prm_set_mod_reg_bits(OMAP_RST_DPLL3_MASK, WKUP_MOD, +				   OMAP2_RM_RSTCTRL); +	/* OCP barrier */ +	omap2_prm_read_mod_reg(WKUP_MOD, OMAP2_RM_RSTCTRL); +} + +int omap2xxx_clkdm_sleep(struct clockdomain *clkdm) +{ +	omap2_prm_set_mod_reg_bits(OMAP24XX_FORCESTATE_MASK, +				   clkdm->pwrdm.ptr->prcm_offs, +				   OMAP2_PM_PWSTCTRL); +	return 0; +} + +int omap2xxx_clkdm_wakeup(struct clockdomain *clkdm) +{ +	omap2_prm_clear_mod_reg_bits(OMAP24XX_FORCESTATE_MASK, +				     clkdm->pwrdm.ptr->prcm_offs, +				     OMAP2_PM_PWSTCTRL); +	return 0; +} + +static int omap2xxx_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst) +{ +	u8 omap24xx_pwrst; + +	switch (pwrst) { +	case PWRDM_POWER_OFF: +		omap24xx_pwrst = OMAP24XX_PWRDM_POWER_OFF; +		break; +	case PWRDM_POWER_RET: +		omap24xx_pwrst = OMAP24XX_PWRDM_POWER_RET; +		break; +	case PWRDM_POWER_ON: +		omap24xx_pwrst = OMAP24XX_PWRDM_POWER_ON; +		break; +	default: +		return -EINVAL; +	} + +	omap2_prm_rmw_mod_reg_bits(OMAP_POWERSTATE_MASK, +				   (omap24xx_pwrst << OMAP_POWERSTATE_SHIFT), +				   pwrdm->prcm_offs, OMAP2_PM_PWSTCTRL); +	return 0; +} + +static int omap2xxx_pwrdm_read_next_pwrst(struct powerdomain *pwrdm) +{ +	u8 omap2xxx_pwrst; + +	omap2xxx_pwrst = omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs, +						       OMAP2_PM_PWSTCTRL, +						       OMAP_POWERSTATE_MASK); + +	return omap2xxx_pwrst_to_common_pwrst(omap2xxx_pwrst); +} + +static int omap2xxx_pwrdm_read_pwrst(struct powerdomain *pwrdm) +{ +	u8 omap2xxx_pwrst; + +	omap2xxx_pwrst = omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs, +						       OMAP2_PM_PWSTST, +						       OMAP_POWERSTATEST_MASK); + +	return omap2xxx_pwrst_to_common_pwrst(omap2xxx_pwrst); +} + +struct pwrdm_ops omap2_pwrdm_operations = { +	.pwrdm_set_next_pwrst	= omap2xxx_pwrdm_set_next_pwrst, +	.pwrdm_read_next_pwrst	= omap2xxx_pwrdm_read_next_pwrst, +	.pwrdm_read_pwrst	= omap2xxx_pwrdm_read_pwrst, +	.pwrdm_set_logic_retst	= omap2_pwrdm_set_logic_retst, +	.pwrdm_set_mem_onst	= omap2_pwrdm_set_mem_onst, +	.pwrdm_set_mem_retst	= omap2_pwrdm_set_mem_retst, +	.pwrdm_read_mem_pwrst	= omap2_pwrdm_read_mem_pwrst, +	.pwrdm_read_mem_retst	= omap2_pwrdm_read_mem_retst, +	.pwrdm_wait_transition	= omap2_pwrdm_wait_transition, +}; + +/* + * + */ + +static struct prm_ll_data omap2xxx_prm_ll_data = { +	.read_reset_sources = &omap2xxx_prm_read_reset_sources, +}; + +int __init omap2xxx_prm_init(void) +{ +	return prm_register(&omap2xxx_prm_ll_data); +} + +static void __exit omap2xxx_prm_exit(void) +{ +	prm_unregister(&omap2xxx_prm_ll_data); +} +__exitcall(omap2xxx_prm_exit);  | 
