xref: /OK3568_Linux_fs/kernel/arch/arm/mach-omap2/prm2xxx.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * OMAP2xxx PRM module functions
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2010-2012 Texas Instruments, Inc.
6*4882a593Smuzhiyun  * Copyright (C) 2010 Nokia Corporation
7*4882a593Smuzhiyun  * Benoît Cousson
8*4882a593Smuzhiyun  * Paul Walmsley
9*4882a593Smuzhiyun  * Rajendra Nayak <rnayak@ti.com>
10*4882a593Smuzhiyun  */
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #include <linux/kernel.h>
13*4882a593Smuzhiyun #include <linux/errno.h>
14*4882a593Smuzhiyun #include <linux/err.h>
15*4882a593Smuzhiyun #include <linux/io.h>
16*4882a593Smuzhiyun #include <linux/irq.h>
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun #include "powerdomain.h"
19*4882a593Smuzhiyun #include "clockdomain.h"
20*4882a593Smuzhiyun #include "prm2xxx.h"
21*4882a593Smuzhiyun #include "cm2xxx_3xxx.h"
22*4882a593Smuzhiyun #include "prm-regbits-24xx.h"
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun /*
25*4882a593Smuzhiyun  * OMAP24xx PM_PWSTCTRL_*.POWERSTATE and PM_PWSTST_*.LASTSTATEENTERED bits -
26*4882a593Smuzhiyun  * these are reversed from the bits used on OMAP3+
27*4882a593Smuzhiyun  */
28*4882a593Smuzhiyun #define OMAP24XX_PWRDM_POWER_ON			0x0
29*4882a593Smuzhiyun #define OMAP24XX_PWRDM_POWER_RET		0x1
30*4882a593Smuzhiyun #define OMAP24XX_PWRDM_POWER_OFF		0x3
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun /*
33*4882a593Smuzhiyun  * omap2xxx_prm_reset_src_map - map from bits in the PRM_RSTST_WKUP
34*4882a593Smuzhiyun  *   hardware register (which are specific to the OMAP2xxx SoCs) to
35*4882a593Smuzhiyun  *   reset source ID bit shifts (which is an OMAP SoC-independent
36*4882a593Smuzhiyun  *   enumeration)
37*4882a593Smuzhiyun  */
38*4882a593Smuzhiyun static struct prm_reset_src_map omap2xxx_prm_reset_src_map[] = {
39*4882a593Smuzhiyun 	{ OMAP_GLOBALCOLD_RST_SHIFT, OMAP_GLOBAL_COLD_RST_SRC_ID_SHIFT },
40*4882a593Smuzhiyun 	{ OMAP_GLOBALWARM_RST_SHIFT, OMAP_GLOBAL_WARM_RST_SRC_ID_SHIFT },
41*4882a593Smuzhiyun 	{ OMAP24XX_SECU_VIOL_RST_SHIFT, OMAP_SECU_VIOL_RST_SRC_ID_SHIFT },
42*4882a593Smuzhiyun 	{ OMAP24XX_MPU_WD_RST_SHIFT, OMAP_MPU_WD_RST_SRC_ID_SHIFT },
43*4882a593Smuzhiyun 	{ OMAP24XX_SECU_WD_RST_SHIFT, OMAP_SECU_WD_RST_SRC_ID_SHIFT },
44*4882a593Smuzhiyun 	{ OMAP24XX_EXTWMPU_RST_SHIFT, OMAP_EXTWARM_RST_SRC_ID_SHIFT },
45*4882a593Smuzhiyun 	{ -1, -1 },
46*4882a593Smuzhiyun };
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun /**
49*4882a593Smuzhiyun  * omap2xxx_prm_read_reset_sources - return the last SoC reset source
50*4882a593Smuzhiyun  *
51*4882a593Smuzhiyun  * Return a u32 representing the last reset sources of the SoC.  The
52*4882a593Smuzhiyun  * returned reset source bits are standardized across OMAP SoCs.
53*4882a593Smuzhiyun  */
omap2xxx_prm_read_reset_sources(void)54*4882a593Smuzhiyun static u32 omap2xxx_prm_read_reset_sources(void)
55*4882a593Smuzhiyun {
56*4882a593Smuzhiyun 	struct prm_reset_src_map *p;
57*4882a593Smuzhiyun 	u32 r = 0;
58*4882a593Smuzhiyun 	u32 v;
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun 	v = omap2_prm_read_mod_reg(WKUP_MOD, OMAP2_RM_RSTST);
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun 	p = omap2xxx_prm_reset_src_map;
63*4882a593Smuzhiyun 	while (p->reg_shift >= 0 && p->std_shift >= 0) {
64*4882a593Smuzhiyun 		if (v & (1 << p->reg_shift))
65*4882a593Smuzhiyun 			r |= 1 << p->std_shift;
66*4882a593Smuzhiyun 		p++;
67*4882a593Smuzhiyun 	}
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun 	return r;
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun /**
73*4882a593Smuzhiyun  * omap2xxx_pwrst_to_common_pwrst - convert OMAP2xxx pwrst to common pwrst
74*4882a593Smuzhiyun  * @omap2xxx_pwrst: OMAP2xxx hardware power state to convert
75*4882a593Smuzhiyun  *
76*4882a593Smuzhiyun  * Return the common power state bits corresponding to the OMAP2xxx
77*4882a593Smuzhiyun  * hardware power state bits @omap2xxx_pwrst, or -EINVAL upon error.
78*4882a593Smuzhiyun  */
omap2xxx_pwrst_to_common_pwrst(u8 omap2xxx_pwrst)79*4882a593Smuzhiyun static int omap2xxx_pwrst_to_common_pwrst(u8 omap2xxx_pwrst)
80*4882a593Smuzhiyun {
81*4882a593Smuzhiyun 	u8 pwrst;
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun 	switch (omap2xxx_pwrst) {
84*4882a593Smuzhiyun 	case OMAP24XX_PWRDM_POWER_OFF:
85*4882a593Smuzhiyun 		pwrst = PWRDM_POWER_OFF;
86*4882a593Smuzhiyun 		break;
87*4882a593Smuzhiyun 	case OMAP24XX_PWRDM_POWER_RET:
88*4882a593Smuzhiyun 		pwrst = PWRDM_POWER_RET;
89*4882a593Smuzhiyun 		break;
90*4882a593Smuzhiyun 	case OMAP24XX_PWRDM_POWER_ON:
91*4882a593Smuzhiyun 		pwrst = PWRDM_POWER_ON;
92*4882a593Smuzhiyun 		break;
93*4882a593Smuzhiyun 	default:
94*4882a593Smuzhiyun 		return -EINVAL;
95*4882a593Smuzhiyun 	}
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun 	return pwrst;
98*4882a593Smuzhiyun }
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun /**
101*4882a593Smuzhiyun  * omap2xxx_prm_dpll_reset - use DPLL reset to reboot the OMAP SoC
102*4882a593Smuzhiyun  *
103*4882a593Smuzhiyun  * Set the DPLL reset bit, which should reboot the SoC.  This is the
104*4882a593Smuzhiyun  * recommended way to restart the SoC.  No return value.
105*4882a593Smuzhiyun  */
omap2xxx_prm_dpll_reset(void)106*4882a593Smuzhiyun static void omap2xxx_prm_dpll_reset(void)
107*4882a593Smuzhiyun {
108*4882a593Smuzhiyun 	omap2_prm_set_mod_reg_bits(OMAP_RST_DPLL3_MASK, WKUP_MOD,
109*4882a593Smuzhiyun 				   OMAP2_RM_RSTCTRL);
110*4882a593Smuzhiyun 	/* OCP barrier */
111*4882a593Smuzhiyun 	omap2_prm_read_mod_reg(WKUP_MOD, OMAP2_RM_RSTCTRL);
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun /**
115*4882a593Smuzhiyun  * omap2xxx_prm_clear_mod_irqs - clear wakeup status bits for a module
116*4882a593Smuzhiyun  * @module: PRM module to clear wakeups from
117*4882a593Smuzhiyun  * @regs: register offset to clear
118*4882a593Smuzhiyun  * @wkst_mask: wakeup status mask to clear
119*4882a593Smuzhiyun  *
120*4882a593Smuzhiyun  * Clears wakeup status bits for a given module, so that the device can
121*4882a593Smuzhiyun  * re-enter idle.
122*4882a593Smuzhiyun  */
omap2xxx_prm_clear_mod_irqs(s16 module,u8 regs,u32 wkst_mask)123*4882a593Smuzhiyun static int omap2xxx_prm_clear_mod_irqs(s16 module, u8 regs, u32 wkst_mask)
124*4882a593Smuzhiyun {
125*4882a593Smuzhiyun 	u32 wkst;
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	wkst = omap2_prm_read_mod_reg(module, regs);
128*4882a593Smuzhiyun 	wkst &= wkst_mask;
129*4882a593Smuzhiyun 	omap2_prm_write_mod_reg(wkst, module, regs);
130*4882a593Smuzhiyun 	return 0;
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun 
omap2xxx_clkdm_sleep(struct clockdomain * clkdm)133*4882a593Smuzhiyun int omap2xxx_clkdm_sleep(struct clockdomain *clkdm)
134*4882a593Smuzhiyun {
135*4882a593Smuzhiyun 	omap2_prm_set_mod_reg_bits(OMAP24XX_FORCESTATE_MASK,
136*4882a593Smuzhiyun 				   clkdm->pwrdm.ptr->prcm_offs,
137*4882a593Smuzhiyun 				   OMAP2_PM_PWSTCTRL);
138*4882a593Smuzhiyun 	return 0;
139*4882a593Smuzhiyun }
140*4882a593Smuzhiyun 
omap2xxx_clkdm_wakeup(struct clockdomain * clkdm)141*4882a593Smuzhiyun int omap2xxx_clkdm_wakeup(struct clockdomain *clkdm)
142*4882a593Smuzhiyun {
143*4882a593Smuzhiyun 	omap2_prm_clear_mod_reg_bits(OMAP24XX_FORCESTATE_MASK,
144*4882a593Smuzhiyun 				     clkdm->pwrdm.ptr->prcm_offs,
145*4882a593Smuzhiyun 				     OMAP2_PM_PWSTCTRL);
146*4882a593Smuzhiyun 	return 0;
147*4882a593Smuzhiyun }
148*4882a593Smuzhiyun 
omap2xxx_pwrdm_set_next_pwrst(struct powerdomain * pwrdm,u8 pwrst)149*4882a593Smuzhiyun static int omap2xxx_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst)
150*4882a593Smuzhiyun {
151*4882a593Smuzhiyun 	u8 omap24xx_pwrst;
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 	switch (pwrst) {
154*4882a593Smuzhiyun 	case PWRDM_POWER_OFF:
155*4882a593Smuzhiyun 		omap24xx_pwrst = OMAP24XX_PWRDM_POWER_OFF;
156*4882a593Smuzhiyun 		break;
157*4882a593Smuzhiyun 	case PWRDM_POWER_RET:
158*4882a593Smuzhiyun 		omap24xx_pwrst = OMAP24XX_PWRDM_POWER_RET;
159*4882a593Smuzhiyun 		break;
160*4882a593Smuzhiyun 	case PWRDM_POWER_ON:
161*4882a593Smuzhiyun 		omap24xx_pwrst = OMAP24XX_PWRDM_POWER_ON;
162*4882a593Smuzhiyun 		break;
163*4882a593Smuzhiyun 	default:
164*4882a593Smuzhiyun 		return -EINVAL;
165*4882a593Smuzhiyun 	}
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 	omap2_prm_rmw_mod_reg_bits(OMAP_POWERSTATE_MASK,
168*4882a593Smuzhiyun 				   (omap24xx_pwrst << OMAP_POWERSTATE_SHIFT),
169*4882a593Smuzhiyun 				   pwrdm->prcm_offs, OMAP2_PM_PWSTCTRL);
170*4882a593Smuzhiyun 	return 0;
171*4882a593Smuzhiyun }
172*4882a593Smuzhiyun 
omap2xxx_pwrdm_read_next_pwrst(struct powerdomain * pwrdm)173*4882a593Smuzhiyun static int omap2xxx_pwrdm_read_next_pwrst(struct powerdomain *pwrdm)
174*4882a593Smuzhiyun {
175*4882a593Smuzhiyun 	u8 omap2xxx_pwrst;
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun 	omap2xxx_pwrst = omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs,
178*4882a593Smuzhiyun 						       OMAP2_PM_PWSTCTRL,
179*4882a593Smuzhiyun 						       OMAP_POWERSTATE_MASK);
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 	return omap2xxx_pwrst_to_common_pwrst(omap2xxx_pwrst);
182*4882a593Smuzhiyun }
183*4882a593Smuzhiyun 
omap2xxx_pwrdm_read_pwrst(struct powerdomain * pwrdm)184*4882a593Smuzhiyun static int omap2xxx_pwrdm_read_pwrst(struct powerdomain *pwrdm)
185*4882a593Smuzhiyun {
186*4882a593Smuzhiyun 	u8 omap2xxx_pwrst;
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	omap2xxx_pwrst = omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs,
189*4882a593Smuzhiyun 						       OMAP2_PM_PWSTST,
190*4882a593Smuzhiyun 						       OMAP_POWERSTATEST_MASK);
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 	return omap2xxx_pwrst_to_common_pwrst(omap2xxx_pwrst);
193*4882a593Smuzhiyun }
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun struct pwrdm_ops omap2_pwrdm_operations = {
196*4882a593Smuzhiyun 	.pwrdm_set_next_pwrst	= omap2xxx_pwrdm_set_next_pwrst,
197*4882a593Smuzhiyun 	.pwrdm_read_next_pwrst	= omap2xxx_pwrdm_read_next_pwrst,
198*4882a593Smuzhiyun 	.pwrdm_read_pwrst	= omap2xxx_pwrdm_read_pwrst,
199*4882a593Smuzhiyun 	.pwrdm_set_logic_retst	= omap2_pwrdm_set_logic_retst,
200*4882a593Smuzhiyun 	.pwrdm_set_mem_onst	= omap2_pwrdm_set_mem_onst,
201*4882a593Smuzhiyun 	.pwrdm_set_mem_retst	= omap2_pwrdm_set_mem_retst,
202*4882a593Smuzhiyun 	.pwrdm_read_mem_pwrst	= omap2_pwrdm_read_mem_pwrst,
203*4882a593Smuzhiyun 	.pwrdm_read_mem_retst	= omap2_pwrdm_read_mem_retst,
204*4882a593Smuzhiyun 	.pwrdm_wait_transition	= omap2_pwrdm_wait_transition,
205*4882a593Smuzhiyun };
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun /*
208*4882a593Smuzhiyun  *
209*4882a593Smuzhiyun  */
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun static struct prm_ll_data omap2xxx_prm_ll_data = {
212*4882a593Smuzhiyun 	.read_reset_sources = &omap2xxx_prm_read_reset_sources,
213*4882a593Smuzhiyun 	.assert_hardreset = &omap2_prm_assert_hardreset,
214*4882a593Smuzhiyun 	.deassert_hardreset = &omap2_prm_deassert_hardreset,
215*4882a593Smuzhiyun 	.is_hardreset_asserted = &omap2_prm_is_hardreset_asserted,
216*4882a593Smuzhiyun 	.reset_system = &omap2xxx_prm_dpll_reset,
217*4882a593Smuzhiyun 	.clear_mod_irqs = &omap2xxx_prm_clear_mod_irqs,
218*4882a593Smuzhiyun };
219*4882a593Smuzhiyun 
omap2xxx_prm_init(const struct omap_prcm_init_data * data)220*4882a593Smuzhiyun int __init omap2xxx_prm_init(const struct omap_prcm_init_data *data)
221*4882a593Smuzhiyun {
222*4882a593Smuzhiyun 	return prm_register(&omap2xxx_prm_ll_data);
223*4882a593Smuzhiyun }
224*4882a593Smuzhiyun 
omap2xxx_prm_exit(void)225*4882a593Smuzhiyun static void __exit omap2xxx_prm_exit(void)
226*4882a593Smuzhiyun {
227*4882a593Smuzhiyun 	prm_unregister(&omap2xxx_prm_ll_data);
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun __exitcall(omap2xxx_prm_exit);
230