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