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 */ 41static 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 */ 57static 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 */ 82static 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 */ 109static 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/** 118 * omap2xxx_prm_clear_mod_irqs - clear wakeup status bits for a module 119 * @module: PRM module to clear wakeups from 120 * @regs: register offset to clear 121 * @wkst_mask: wakeup status mask to clear 122 * 123 * Clears wakeup status bits for a given module, so that the device can 124 * re-enter idle. 125 */ 126static int omap2xxx_prm_clear_mod_irqs(s16 module, u8 regs, u32 wkst_mask) 127{ 128 u32 wkst; 129 130 wkst = omap2_prm_read_mod_reg(module, regs); 131 wkst &= wkst_mask; 132 omap2_prm_write_mod_reg(wkst, module, regs); 133 return 0; 134} 135 136int omap2xxx_clkdm_sleep(struct clockdomain *clkdm) 137{ 138 omap2_prm_set_mod_reg_bits(OMAP24XX_FORCESTATE_MASK, 139 clkdm->pwrdm.ptr->prcm_offs, 140 OMAP2_PM_PWSTCTRL); 141 return 0; 142} 143 144int omap2xxx_clkdm_wakeup(struct clockdomain *clkdm) 145{ 146 omap2_prm_clear_mod_reg_bits(OMAP24XX_FORCESTATE_MASK, 147 clkdm->pwrdm.ptr->prcm_offs, 148 OMAP2_PM_PWSTCTRL); 149 return 0; 150} 151 152static int omap2xxx_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst) 153{ 154 u8 omap24xx_pwrst; 155 156 switch (pwrst) { 157 case PWRDM_POWER_OFF: 158 omap24xx_pwrst = OMAP24XX_PWRDM_POWER_OFF; 159 break; 160 case PWRDM_POWER_RET: 161 omap24xx_pwrst = OMAP24XX_PWRDM_POWER_RET; 162 break; 163 case PWRDM_POWER_ON: 164 omap24xx_pwrst = OMAP24XX_PWRDM_POWER_ON; 165 break; 166 default: 167 return -EINVAL; 168 } 169 170 omap2_prm_rmw_mod_reg_bits(OMAP_POWERSTATE_MASK, 171 (omap24xx_pwrst << OMAP_POWERSTATE_SHIFT), 172 pwrdm->prcm_offs, OMAP2_PM_PWSTCTRL); 173 return 0; 174} 175 176static int omap2xxx_pwrdm_read_next_pwrst(struct powerdomain *pwrdm) 177{ 178 u8 omap2xxx_pwrst; 179 180 omap2xxx_pwrst = omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs, 181 OMAP2_PM_PWSTCTRL, 182 OMAP_POWERSTATE_MASK); 183 184 return omap2xxx_pwrst_to_common_pwrst(omap2xxx_pwrst); 185} 186 187static int omap2xxx_pwrdm_read_pwrst(struct powerdomain *pwrdm) 188{ 189 u8 omap2xxx_pwrst; 190 191 omap2xxx_pwrst = omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs, 192 OMAP2_PM_PWSTST, 193 OMAP_POWERSTATEST_MASK); 194 195 return omap2xxx_pwrst_to_common_pwrst(omap2xxx_pwrst); 196} 197 198struct pwrdm_ops omap2_pwrdm_operations = { 199 .pwrdm_set_next_pwrst = omap2xxx_pwrdm_set_next_pwrst, 200 .pwrdm_read_next_pwrst = omap2xxx_pwrdm_read_next_pwrst, 201 .pwrdm_read_pwrst = omap2xxx_pwrdm_read_pwrst, 202 .pwrdm_set_logic_retst = omap2_pwrdm_set_logic_retst, 203 .pwrdm_set_mem_onst = omap2_pwrdm_set_mem_onst, 204 .pwrdm_set_mem_retst = omap2_pwrdm_set_mem_retst, 205 .pwrdm_read_mem_pwrst = omap2_pwrdm_read_mem_pwrst, 206 .pwrdm_read_mem_retst = omap2_pwrdm_read_mem_retst, 207 .pwrdm_wait_transition = omap2_pwrdm_wait_transition, 208}; 209 210/* 211 * 212 */ 213 214static struct prm_ll_data omap2xxx_prm_ll_data = { 215 .read_reset_sources = &omap2xxx_prm_read_reset_sources, 216 .assert_hardreset = &omap2_prm_assert_hardreset, 217 .deassert_hardreset = &omap2_prm_deassert_hardreset, 218 .is_hardreset_asserted = &omap2_prm_is_hardreset_asserted, 219 .reset_system = &omap2xxx_prm_dpll_reset, 220 .clear_mod_irqs = &omap2xxx_prm_clear_mod_irqs, 221}; 222 223int __init omap2xxx_prm_init(const struct omap_prcm_init_data *data) 224{ 225 return prm_register(&omap2xxx_prm_ll_data); 226} 227 228static void __exit omap2xxx_prm_exit(void) 229{ 230 prm_unregister(&omap2xxx_prm_ll_data); 231} 232__exitcall(omap2xxx_prm_exit); 233