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