xref: /openbmc/linux/arch/arm/mach-omap2/prm2xxx.c (revision 61c8621e)
149815399SPaul Walmsley /*
249815399SPaul Walmsley  * OMAP2xxx PRM module functions
349815399SPaul Walmsley  *
449815399SPaul Walmsley  * Copyright (C) 2010-2012 Texas Instruments, Inc.
549815399SPaul Walmsley  * Copyright (C) 2010 Nokia Corporation
649815399SPaul Walmsley  * Benoît Cousson
749815399SPaul Walmsley  * Paul Walmsley
849815399SPaul Walmsley  * Rajendra Nayak <rnayak@ti.com>
949815399SPaul Walmsley  *
1049815399SPaul Walmsley  * This program is free software; you can redistribute it and/or modify
1149815399SPaul Walmsley  * it under the terms of the GNU General Public License version 2 as
1249815399SPaul Walmsley  * published by the Free Software Foundation.
1349815399SPaul Walmsley  */
1449815399SPaul Walmsley 
1549815399SPaul Walmsley #include <linux/kernel.h>
1649815399SPaul Walmsley #include <linux/errno.h>
1749815399SPaul Walmsley #include <linux/err.h>
1849815399SPaul Walmsley #include <linux/io.h>
1949815399SPaul Walmsley #include <linux/irq.h>
2049815399SPaul Walmsley 
2149815399SPaul Walmsley #include "powerdomain.h"
224bd5259eSPaul Walmsley #include "clockdomain.h"
2349815399SPaul Walmsley #include "prm2xxx.h"
2449815399SPaul Walmsley #include "cm2xxx_3xxx.h"
2549815399SPaul Walmsley #include "prm-regbits-24xx.h"
2649815399SPaul Walmsley 
272bb2a5d3SPaul Walmsley /*
287e7fff82SPaul Walmsley  * OMAP24xx PM_PWSTCTRL_*.POWERSTATE and PM_PWSTST_*.LASTSTATEENTERED bits -
297e7fff82SPaul Walmsley  * these are reversed from the bits used on OMAP3+
307e7fff82SPaul Walmsley  */
317e7fff82SPaul Walmsley #define OMAP24XX_PWRDM_POWER_ON			0x0
327e7fff82SPaul Walmsley #define OMAP24XX_PWRDM_POWER_RET		0x1
337e7fff82SPaul Walmsley #define OMAP24XX_PWRDM_POWER_OFF		0x3
347e7fff82SPaul Walmsley 
357e7fff82SPaul Walmsley /*
362bb2a5d3SPaul Walmsley  * omap2xxx_prm_reset_src_map - map from bits in the PRM_RSTST_WKUP
372bb2a5d3SPaul Walmsley  *   hardware register (which are specific to the OMAP2xxx SoCs) to
382bb2a5d3SPaul Walmsley  *   reset source ID bit shifts (which is an OMAP SoC-independent
392bb2a5d3SPaul Walmsley  *   enumeration)
402bb2a5d3SPaul Walmsley  */
412bb2a5d3SPaul Walmsley static struct prm_reset_src_map omap2xxx_prm_reset_src_map[] = {
422bb2a5d3SPaul Walmsley 	{ OMAP_GLOBALCOLD_RST_SHIFT, OMAP_GLOBAL_COLD_RST_SRC_ID_SHIFT },
432bb2a5d3SPaul Walmsley 	{ OMAP_GLOBALWARM_RST_SHIFT, OMAP_GLOBAL_WARM_RST_SRC_ID_SHIFT },
442bb2a5d3SPaul Walmsley 	{ OMAP24XX_SECU_VIOL_RST_SHIFT, OMAP_SECU_VIOL_RST_SRC_ID_SHIFT },
452bb2a5d3SPaul Walmsley 	{ OMAP24XX_MPU_WD_RST_SHIFT, OMAP_MPU_WD_RST_SRC_ID_SHIFT },
462bb2a5d3SPaul Walmsley 	{ OMAP24XX_SECU_WD_RST_SHIFT, OMAP_SECU_WD_RST_SRC_ID_SHIFT },
472bb2a5d3SPaul Walmsley 	{ OMAP24XX_EXTWMPU_RST_SHIFT, OMAP_EXTWARM_RST_SRC_ID_SHIFT },
482bb2a5d3SPaul Walmsley 	{ -1, -1 },
492bb2a5d3SPaul Walmsley };
502bb2a5d3SPaul Walmsley 
512bb2a5d3SPaul Walmsley /**
522bb2a5d3SPaul Walmsley  * omap2xxx_prm_read_reset_sources - return the last SoC reset source
532bb2a5d3SPaul Walmsley  *
542bb2a5d3SPaul Walmsley  * Return a u32 representing the last reset sources of the SoC.  The
552bb2a5d3SPaul Walmsley  * returned reset source bits are standardized across OMAP SoCs.
562bb2a5d3SPaul Walmsley  */
572bb2a5d3SPaul Walmsley static u32 omap2xxx_prm_read_reset_sources(void)
582bb2a5d3SPaul Walmsley {
592bb2a5d3SPaul Walmsley 	struct prm_reset_src_map *p;
602bb2a5d3SPaul Walmsley 	u32 r = 0;
612bb2a5d3SPaul Walmsley 	u32 v;
622bb2a5d3SPaul Walmsley 
632bb2a5d3SPaul Walmsley 	v = omap2_prm_read_mod_reg(WKUP_MOD, OMAP2_RM_RSTST);
642bb2a5d3SPaul Walmsley 
652bb2a5d3SPaul Walmsley 	p = omap2xxx_prm_reset_src_map;
662bb2a5d3SPaul Walmsley 	while (p->reg_shift >= 0 && p->std_shift >= 0) {
672bb2a5d3SPaul Walmsley 		if (v & (1 << p->reg_shift))
682bb2a5d3SPaul Walmsley 			r |= 1 << p->std_shift;
692bb2a5d3SPaul Walmsley 		p++;
702bb2a5d3SPaul Walmsley 	}
712bb2a5d3SPaul Walmsley 
722bb2a5d3SPaul Walmsley 	return r;
732bb2a5d3SPaul Walmsley }
742bb2a5d3SPaul Walmsley 
75d08cce6aSPaul Walmsley /**
767e7fff82SPaul Walmsley  * omap2xxx_pwrst_to_common_pwrst - convert OMAP2xxx pwrst to common pwrst
777e7fff82SPaul Walmsley  * @omap2xxx_pwrst: OMAP2xxx hardware power state to convert
787e7fff82SPaul Walmsley  *
797e7fff82SPaul Walmsley  * Return the common power state bits corresponding to the OMAP2xxx
807e7fff82SPaul Walmsley  * hardware power state bits @omap2xxx_pwrst, or -EINVAL upon error.
817e7fff82SPaul Walmsley  */
827e7fff82SPaul Walmsley static int omap2xxx_pwrst_to_common_pwrst(u8 omap2xxx_pwrst)
837e7fff82SPaul Walmsley {
847e7fff82SPaul Walmsley 	u8 pwrst;
857e7fff82SPaul Walmsley 
867e7fff82SPaul Walmsley 	switch (omap2xxx_pwrst) {
877e7fff82SPaul Walmsley 	case OMAP24XX_PWRDM_POWER_OFF:
887e7fff82SPaul Walmsley 		pwrst = PWRDM_POWER_OFF;
897e7fff82SPaul Walmsley 		break;
907e7fff82SPaul Walmsley 	case OMAP24XX_PWRDM_POWER_RET:
917e7fff82SPaul Walmsley 		pwrst = PWRDM_POWER_RET;
927e7fff82SPaul Walmsley 		break;
937e7fff82SPaul Walmsley 	case OMAP24XX_PWRDM_POWER_ON:
947e7fff82SPaul Walmsley 		pwrst = PWRDM_POWER_ON;
957e7fff82SPaul Walmsley 		break;
967e7fff82SPaul Walmsley 	default:
977e7fff82SPaul Walmsley 		return -EINVAL;
987e7fff82SPaul Walmsley 	}
997e7fff82SPaul Walmsley 
1007e7fff82SPaul Walmsley 	return pwrst;
1017e7fff82SPaul Walmsley }
1027e7fff82SPaul Walmsley 
1037e7fff82SPaul Walmsley /**
104d08cce6aSPaul Walmsley  * omap2xxx_prm_dpll_reset - use DPLL reset to reboot the OMAP SoC
105d08cce6aSPaul Walmsley  *
106d08cce6aSPaul Walmsley  * Set the DPLL reset bit, which should reboot the SoC.  This is the
107d08cce6aSPaul Walmsley  * recommended way to restart the SoC.  No return value.
108d08cce6aSPaul Walmsley  */
10961c8621eSTero Kristo static void omap2xxx_prm_dpll_reset(void)
110d08cce6aSPaul Walmsley {
111d08cce6aSPaul Walmsley 	omap2_prm_set_mod_reg_bits(OMAP_RST_DPLL3_MASK, WKUP_MOD,
112d08cce6aSPaul Walmsley 				   OMAP2_RM_RSTCTRL);
113d08cce6aSPaul Walmsley 	/* OCP barrier */
114d08cce6aSPaul Walmsley 	omap2_prm_read_mod_reg(WKUP_MOD, OMAP2_RM_RSTCTRL);
115d08cce6aSPaul Walmsley }
116d08cce6aSPaul Walmsley 
1176bdc4b44STero Kristo /**
1186bdc4b44STero Kristo  * omap2xxx_prm_clear_mod_irqs - clear wakeup status bits for a module
1196bdc4b44STero Kristo  * @module: PRM module to clear wakeups from
1206bdc4b44STero Kristo  * @regs: register offset to clear
1216bdc4b44STero Kristo  * @wkst_mask: wakeup status mask to clear
1226bdc4b44STero Kristo  *
1236bdc4b44STero Kristo  * Clears wakeup status bits for a given module, so that the device can
1246bdc4b44STero Kristo  * re-enter idle.
1256bdc4b44STero Kristo  */
1266bdc4b44STero Kristo void omap2xxx_prm_clear_mod_irqs(s16 module, u8 regs, u32 wkst_mask)
1276bdc4b44STero Kristo {
1286bdc4b44STero Kristo 	u32 wkst;
1296bdc4b44STero Kristo 
1306bdc4b44STero Kristo 	wkst = omap2_prm_read_mod_reg(module, regs);
1316bdc4b44STero Kristo 	wkst &= wkst_mask;
1326bdc4b44STero Kristo 	omap2_prm_write_mod_reg(wkst, module, regs);
1336bdc4b44STero Kristo }
1346bdc4b44STero Kristo 
1354bd5259eSPaul Walmsley int omap2xxx_clkdm_sleep(struct clockdomain *clkdm)
1364bd5259eSPaul Walmsley {
1374bd5259eSPaul Walmsley 	omap2_prm_set_mod_reg_bits(OMAP24XX_FORCESTATE_MASK,
1384bd5259eSPaul Walmsley 				   clkdm->pwrdm.ptr->prcm_offs,
1394bd5259eSPaul Walmsley 				   OMAP2_PM_PWSTCTRL);
1404bd5259eSPaul Walmsley 	return 0;
1414bd5259eSPaul Walmsley }
1424bd5259eSPaul Walmsley 
1434bd5259eSPaul Walmsley int omap2xxx_clkdm_wakeup(struct clockdomain *clkdm)
1444bd5259eSPaul Walmsley {
1454bd5259eSPaul Walmsley 	omap2_prm_clear_mod_reg_bits(OMAP24XX_FORCESTATE_MASK,
1464bd5259eSPaul Walmsley 				     clkdm->pwrdm.ptr->prcm_offs,
1474bd5259eSPaul Walmsley 				     OMAP2_PM_PWSTCTRL);
1484bd5259eSPaul Walmsley 	return 0;
1494bd5259eSPaul Walmsley }
1504bd5259eSPaul Walmsley 
1517e7fff82SPaul Walmsley static int omap2xxx_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst)
1527e7fff82SPaul Walmsley {
1537e7fff82SPaul Walmsley 	u8 omap24xx_pwrst;
1547e7fff82SPaul Walmsley 
1557e7fff82SPaul Walmsley 	switch (pwrst) {
1567e7fff82SPaul Walmsley 	case PWRDM_POWER_OFF:
1577e7fff82SPaul Walmsley 		omap24xx_pwrst = OMAP24XX_PWRDM_POWER_OFF;
1587e7fff82SPaul Walmsley 		break;
1597e7fff82SPaul Walmsley 	case PWRDM_POWER_RET:
1607e7fff82SPaul Walmsley 		omap24xx_pwrst = OMAP24XX_PWRDM_POWER_RET;
1617e7fff82SPaul Walmsley 		break;
1627e7fff82SPaul Walmsley 	case PWRDM_POWER_ON:
1637e7fff82SPaul Walmsley 		omap24xx_pwrst = OMAP24XX_PWRDM_POWER_ON;
1647e7fff82SPaul Walmsley 		break;
1657e7fff82SPaul Walmsley 	default:
1667e7fff82SPaul Walmsley 		return -EINVAL;
1677e7fff82SPaul Walmsley 	}
1687e7fff82SPaul Walmsley 
1697e7fff82SPaul Walmsley 	omap2_prm_rmw_mod_reg_bits(OMAP_POWERSTATE_MASK,
1707e7fff82SPaul Walmsley 				   (omap24xx_pwrst << OMAP_POWERSTATE_SHIFT),
1717e7fff82SPaul Walmsley 				   pwrdm->prcm_offs, OMAP2_PM_PWSTCTRL);
1727e7fff82SPaul Walmsley 	return 0;
1737e7fff82SPaul Walmsley }
1747e7fff82SPaul Walmsley 
1757e7fff82SPaul Walmsley static int omap2xxx_pwrdm_read_next_pwrst(struct powerdomain *pwrdm)
1767e7fff82SPaul Walmsley {
1777e7fff82SPaul Walmsley 	u8 omap2xxx_pwrst;
1787e7fff82SPaul Walmsley 
1797e7fff82SPaul Walmsley 	omap2xxx_pwrst = omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs,
1807e7fff82SPaul Walmsley 						       OMAP2_PM_PWSTCTRL,
1817e7fff82SPaul Walmsley 						       OMAP_POWERSTATE_MASK);
1827e7fff82SPaul Walmsley 
1837e7fff82SPaul Walmsley 	return omap2xxx_pwrst_to_common_pwrst(omap2xxx_pwrst);
1847e7fff82SPaul Walmsley }
1857e7fff82SPaul Walmsley 
1867e7fff82SPaul Walmsley static int omap2xxx_pwrdm_read_pwrst(struct powerdomain *pwrdm)
1877e7fff82SPaul Walmsley {
1887e7fff82SPaul Walmsley 	u8 omap2xxx_pwrst;
1897e7fff82SPaul Walmsley 
1907e7fff82SPaul Walmsley 	omap2xxx_pwrst = omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs,
1917e7fff82SPaul Walmsley 						       OMAP2_PM_PWSTST,
1927e7fff82SPaul Walmsley 						       OMAP_POWERSTATEST_MASK);
1937e7fff82SPaul Walmsley 
1947e7fff82SPaul Walmsley 	return omap2xxx_pwrst_to_common_pwrst(omap2xxx_pwrst);
1957e7fff82SPaul Walmsley }
1967e7fff82SPaul Walmsley 
19749815399SPaul Walmsley struct pwrdm_ops omap2_pwrdm_operations = {
1987e7fff82SPaul Walmsley 	.pwrdm_set_next_pwrst	= omap2xxx_pwrdm_set_next_pwrst,
1997e7fff82SPaul Walmsley 	.pwrdm_read_next_pwrst	= omap2xxx_pwrdm_read_next_pwrst,
2007e7fff82SPaul Walmsley 	.pwrdm_read_pwrst	= omap2xxx_pwrdm_read_pwrst,
20149815399SPaul Walmsley 	.pwrdm_set_logic_retst	= omap2_pwrdm_set_logic_retst,
20249815399SPaul Walmsley 	.pwrdm_set_mem_onst	= omap2_pwrdm_set_mem_onst,
20349815399SPaul Walmsley 	.pwrdm_set_mem_retst	= omap2_pwrdm_set_mem_retst,
20449815399SPaul Walmsley 	.pwrdm_read_mem_pwrst	= omap2_pwrdm_read_mem_pwrst,
20549815399SPaul Walmsley 	.pwrdm_read_mem_retst	= omap2_pwrdm_read_mem_retst,
20649815399SPaul Walmsley 	.pwrdm_wait_transition	= omap2_pwrdm_wait_transition,
20749815399SPaul Walmsley };
2082bb2a5d3SPaul Walmsley 
2092bb2a5d3SPaul Walmsley /*
2102bb2a5d3SPaul Walmsley  *
2112bb2a5d3SPaul Walmsley  */
2122bb2a5d3SPaul Walmsley 
2132bb2a5d3SPaul Walmsley static struct prm_ll_data omap2xxx_prm_ll_data = {
2142bb2a5d3SPaul Walmsley 	.read_reset_sources = &omap2xxx_prm_read_reset_sources,
215efd44dc3STero Kristo 	.assert_hardreset = &omap2_prm_assert_hardreset,
21637fb59d7STero Kristo 	.deassert_hardreset = &omap2_prm_deassert_hardreset,
2171bc28b34STero Kristo 	.is_hardreset_asserted = &omap2_prm_is_hardreset_asserted,
21861c8621eSTero Kristo 	.reset_system = &omap2xxx_prm_dpll_reset,
2192bb2a5d3SPaul Walmsley };
2202bb2a5d3SPaul Walmsley 
22163a293e0SPaul Walmsley int __init omap2xxx_prm_init(void)
2222bb2a5d3SPaul Walmsley {
2232bb2a5d3SPaul Walmsley 	return prm_register(&omap2xxx_prm_ll_data);
2242bb2a5d3SPaul Walmsley }
2252bb2a5d3SPaul Walmsley 
2262bb2a5d3SPaul Walmsley static void __exit omap2xxx_prm_exit(void)
2272bb2a5d3SPaul Walmsley {
228d8871cd2STero Kristo 	prm_unregister(&omap2xxx_prm_ll_data);
2292bb2a5d3SPaul Walmsley }
2302bb2a5d3SPaul Walmsley __exitcall(omap2xxx_prm_exit);
231