| 
									
										
										
										
											2012-10-21 01:01:10 -06:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * 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"
 | 
					
						
							| 
									
										
										
										
											2012-10-21 01:01:11 -06:00
										 |  |  | #include "clockdomain.h"
 | 
					
						
							| 
									
										
										
										
											2012-10-21 01:01:10 -06:00
										 |  |  | #include "prm2xxx.h"
 | 
					
						
							|  |  |  | #include "cm2xxx_3xxx.h"
 | 
					
						
							|  |  |  | #include "prm-regbits-24xx.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
											
												ARM: OMAP2/3: PRM: fix bogus OMAP2xxx powerstate return values
On OMAP2xxx chips, the register bitfields for the
PM_PWSTCTRL_*.POWERSTATE and PM_PWSTST_*.LASTSTATEENTERED are
different than those used on OMAP3/4.  The order is reversed.  So, for
example, on OMAP2xxx, 0x0 indicates 'ON'; but on OMAP3/4, 0x0
indicates 'OFF'.  Similarly, on OMAP2xxx, 0x3 indicates 'OFF', but on
OMAP3/4, 0x3 indicates 'ON'.
To fix this, we treat the OMAP3/4 values as the powerdomain API
values, and create new low-level powerdomain functions for the
OMAP2xxx chips which translate between the OMAP2xxx values and the
OMAP3/4 values.
Without this patch, the conversion of the OMAP2xxx PM code to the
functional powerstate code results in a non-booting kernel.
Signed-off-by: Paul Walmsley <paul@pwsan.com>
											
										 
											2012-12-28 02:10:44 -07:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * 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
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-21 01:01:13 -06:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * 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; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
											
												ARM: OMAP2/3: PRM: fix bogus OMAP2xxx powerstate return values
On OMAP2xxx chips, the register bitfields for the
PM_PWSTCTRL_*.POWERSTATE and PM_PWSTST_*.LASTSTATEENTERED are
different than those used on OMAP3/4.  The order is reversed.  So, for
example, on OMAP2xxx, 0x0 indicates 'ON'; but on OMAP3/4, 0x0
indicates 'OFF'.  Similarly, on OMAP2xxx, 0x3 indicates 'OFF', but on
OMAP3/4, 0x3 indicates 'ON'.
To fix this, we treat the OMAP3/4 values as the powerdomain API
values, and create new low-level powerdomain functions for the
OMAP2xxx chips which translate between the OMAP2xxx values and the
OMAP3/4 values.
Without this patch, the conversion of the OMAP2xxx PM code to the
functional powerstate code results in a non-booting kernel.
Signed-off-by: Paul Walmsley <paul@pwsan.com>
											
										 
											2012-12-28 02:10:44 -07:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * 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; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-29 20:55:46 -06:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * 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); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-26 15:31:05 +02:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * omap2xxx_prm_clear_mod_irqs - clear wakeup status bits for a module | 
					
						
							|  |  |  |  * @module: PRM module to clear wakeups from | 
					
						
							|  |  |  |  * @regs: register offset to clear | 
					
						
							|  |  |  |  * @wkst_mask: wakeup status mask to clear | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Clears wakeup status bits for a given module, so that the device can | 
					
						
							|  |  |  |  * re-enter idle. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | void omap2xxx_prm_clear_mod_irqs(s16 module, u8 regs, u32 wkst_mask) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	u32 wkst; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	wkst = omap2_prm_read_mod_reg(module, regs); | 
					
						
							|  |  |  | 	wkst &= wkst_mask; | 
					
						
							|  |  |  | 	omap2_prm_write_mod_reg(wkst, module, regs); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-21 01:01:11 -06:00
										 |  |  | 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; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
											
												ARM: OMAP2/3: PRM: fix bogus OMAP2xxx powerstate return values
On OMAP2xxx chips, the register bitfields for the
PM_PWSTCTRL_*.POWERSTATE and PM_PWSTST_*.LASTSTATEENTERED are
different than those used on OMAP3/4.  The order is reversed.  So, for
example, on OMAP2xxx, 0x0 indicates 'ON'; but on OMAP3/4, 0x0
indicates 'OFF'.  Similarly, on OMAP2xxx, 0x3 indicates 'OFF', but on
OMAP3/4, 0x3 indicates 'ON'.
To fix this, we treat the OMAP3/4 values as the powerdomain API
values, and create new low-level powerdomain functions for the
OMAP2xxx chips which translate between the OMAP2xxx values and the
OMAP3/4 values.
Without this patch, the conversion of the OMAP2xxx PM code to the
functional powerstate code results in a non-booting kernel.
Signed-off-by: Paul Walmsley <paul@pwsan.com>
											
										 
											2012-12-28 02:10:44 -07:00
										 |  |  | 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); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-21 01:01:10 -06:00
										 |  |  | struct pwrdm_ops omap2_pwrdm_operations = { | 
					
						
							| 
									
										
										
											
												ARM: OMAP2/3: PRM: fix bogus OMAP2xxx powerstate return values
On OMAP2xxx chips, the register bitfields for the
PM_PWSTCTRL_*.POWERSTATE and PM_PWSTST_*.LASTSTATEENTERED are
different than those used on OMAP3/4.  The order is reversed.  So, for
example, on OMAP2xxx, 0x0 indicates 'ON'; but on OMAP3/4, 0x0
indicates 'OFF'.  Similarly, on OMAP2xxx, 0x3 indicates 'OFF', but on
OMAP3/4, 0x3 indicates 'ON'.
To fix this, we treat the OMAP3/4 values as the powerdomain API
values, and create new low-level powerdomain functions for the
OMAP2xxx chips which translate between the OMAP2xxx values and the
OMAP3/4 values.
Without this patch, the conversion of the OMAP2xxx PM code to the
functional powerstate code results in a non-booting kernel.
Signed-off-by: Paul Walmsley <paul@pwsan.com>
											
										 
											2012-12-28 02:10:44 -07:00
										 |  |  | 	.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, | 
					
						
							| 
									
										
										
										
											2012-10-21 01:01:10 -06:00
										 |  |  | 	.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, | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2012-10-21 01:01:13 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct prm_ll_data omap2xxx_prm_ll_data = { | 
					
						
							|  |  |  | 	.read_reset_sources = &omap2xxx_prm_read_reset_sources, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-21 16:15:16 -07:00
										 |  |  | int __init omap2xxx_prm_init(void) | 
					
						
							| 
									
										
										
										
											2012-10-21 01:01:13 -06:00
										 |  |  | { | 
					
						
							|  |  |  | 	return prm_register(&omap2xxx_prm_ll_data); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void __exit omap2xxx_prm_exit(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2014-05-11 19:54:58 -06:00
										 |  |  | 	prm_unregister(&omap2xxx_prm_ll_data); | 
					
						
							| 
									
										
										
										
											2012-10-21 01:01:13 -06:00
										 |  |  | } | 
					
						
							|  |  |  | __exitcall(omap2xxx_prm_exit); |