linux/arch/arm/mach-omap2/prm2xxx.c
<<
>>
Prefs
   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 "soc.h"
  22#include "common.h"
  23#include "vp.h"
  24#include "powerdomain.h"
  25#include "clockdomain.h"
  26#include "prm2xxx.h"
  27#include "cm2xxx_3xxx.h"
  28#include "prm-regbits-24xx.h"
  29
  30/*
  31 * OMAP24xx PM_PWSTCTRL_*.POWERSTATE and PM_PWSTST_*.LASTSTATEENTERED bits -
  32 * these are reversed from the bits used on OMAP3+
  33 */
  34#define OMAP24XX_PWRDM_POWER_ON                 0x0
  35#define OMAP24XX_PWRDM_POWER_RET                0x1
  36#define OMAP24XX_PWRDM_POWER_OFF                0x3
  37
  38/*
  39 * omap2xxx_prm_reset_src_map - map from bits in the PRM_RSTST_WKUP
  40 *   hardware register (which are specific to the OMAP2xxx SoCs) to
  41 *   reset source ID bit shifts (which is an OMAP SoC-independent
  42 *   enumeration)
  43 */
  44static struct prm_reset_src_map omap2xxx_prm_reset_src_map[] = {
  45        { OMAP_GLOBALCOLD_RST_SHIFT, OMAP_GLOBAL_COLD_RST_SRC_ID_SHIFT },
  46        { OMAP_GLOBALWARM_RST_SHIFT, OMAP_GLOBAL_WARM_RST_SRC_ID_SHIFT },
  47        { OMAP24XX_SECU_VIOL_RST_SHIFT, OMAP_SECU_VIOL_RST_SRC_ID_SHIFT },
  48        { OMAP24XX_MPU_WD_RST_SHIFT, OMAP_MPU_WD_RST_SRC_ID_SHIFT },
  49        { OMAP24XX_SECU_WD_RST_SHIFT, OMAP_SECU_WD_RST_SRC_ID_SHIFT },
  50        { OMAP24XX_EXTWMPU_RST_SHIFT, OMAP_EXTWARM_RST_SRC_ID_SHIFT },
  51        { -1, -1 },
  52};
  53
  54/**
  55 * omap2xxx_prm_read_reset_sources - return the last SoC reset source
  56 *
  57 * Return a u32 representing the last reset sources of the SoC.  The
  58 * returned reset source bits are standardized across OMAP SoCs.
  59 */
  60static u32 omap2xxx_prm_read_reset_sources(void)
  61{
  62        struct prm_reset_src_map *p;
  63        u32 r = 0;
  64        u32 v;
  65
  66        v = omap2_prm_read_mod_reg(WKUP_MOD, OMAP2_RM_RSTST);
  67
  68        p = omap2xxx_prm_reset_src_map;
  69        while (p->reg_shift >= 0 && p->std_shift >= 0) {
  70                if (v & (1 << p->reg_shift))
  71                        r |= 1 << p->std_shift;
  72                p++;
  73        }
  74
  75        return r;
  76}
  77
  78/**
  79 * omap2xxx_pwrst_to_common_pwrst - convert OMAP2xxx pwrst to common pwrst
  80 * @omap2xxx_pwrst: OMAP2xxx hardware power state to convert
  81 *
  82 * Return the common power state bits corresponding to the OMAP2xxx
  83 * hardware power state bits @omap2xxx_pwrst, or -EINVAL upon error.
  84 */
  85static int omap2xxx_pwrst_to_common_pwrst(u8 omap2xxx_pwrst)
  86{
  87        u8 pwrst;
  88
  89        switch (omap2xxx_pwrst) {
  90        case OMAP24XX_PWRDM_POWER_OFF:
  91                pwrst = PWRDM_POWER_OFF;
  92                break;
  93        case OMAP24XX_PWRDM_POWER_RET:
  94                pwrst = PWRDM_POWER_RET;
  95                break;
  96        case OMAP24XX_PWRDM_POWER_ON:
  97                pwrst = PWRDM_POWER_ON;
  98                break;
  99        default:
 100                return -EINVAL;
 101        }
 102
 103        return pwrst;
 104}
 105
 106/**
 107 * omap2xxx_prm_dpll_reset - use DPLL reset to reboot the OMAP SoC
 108 *
 109 * Set the DPLL reset bit, which should reboot the SoC.  This is the
 110 * recommended way to restart the SoC.  No return value.
 111 */
 112void omap2xxx_prm_dpll_reset(void)
 113{
 114        omap2_prm_set_mod_reg_bits(OMAP_RST_DPLL3_MASK, WKUP_MOD,
 115                                   OMAP2_RM_RSTCTRL);
 116        /* OCP barrier */
 117        omap2_prm_read_mod_reg(WKUP_MOD, OMAP2_RM_RSTCTRL);
 118}
 119
 120int omap2xxx_clkdm_sleep(struct clockdomain *clkdm)
 121{
 122        omap2_prm_set_mod_reg_bits(OMAP24XX_FORCESTATE_MASK,
 123                                   clkdm->pwrdm.ptr->prcm_offs,
 124                                   OMAP2_PM_PWSTCTRL);
 125        return 0;
 126}
 127
 128int omap2xxx_clkdm_wakeup(struct clockdomain *clkdm)
 129{
 130        omap2_prm_clear_mod_reg_bits(OMAP24XX_FORCESTATE_MASK,
 131                                     clkdm->pwrdm.ptr->prcm_offs,
 132                                     OMAP2_PM_PWSTCTRL);
 133        return 0;
 134}
 135
 136static int omap2xxx_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst)
 137{
 138        u8 omap24xx_pwrst;
 139
 140        switch (pwrst) {
 141        case PWRDM_POWER_OFF:
 142                omap24xx_pwrst = OMAP24XX_PWRDM_POWER_OFF;
 143                break;
 144        case PWRDM_POWER_RET:
 145                omap24xx_pwrst = OMAP24XX_PWRDM_POWER_RET;
 146                break;
 147        case PWRDM_POWER_ON:
 148                omap24xx_pwrst = OMAP24XX_PWRDM_POWER_ON;
 149                break;
 150        default:
 151                return -EINVAL;
 152        }
 153
 154        omap2_prm_rmw_mod_reg_bits(OMAP_POWERSTATE_MASK,
 155                                   (omap24xx_pwrst << OMAP_POWERSTATE_SHIFT),
 156                                   pwrdm->prcm_offs, OMAP2_PM_PWSTCTRL);
 157        return 0;
 158}
 159
 160static int omap2xxx_pwrdm_read_next_pwrst(struct powerdomain *pwrdm)
 161{
 162        u8 omap2xxx_pwrst;
 163
 164        omap2xxx_pwrst = omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs,
 165                                                       OMAP2_PM_PWSTCTRL,
 166                                                       OMAP_POWERSTATE_MASK);
 167
 168        return omap2xxx_pwrst_to_common_pwrst(omap2xxx_pwrst);
 169}
 170
 171static int omap2xxx_pwrdm_read_pwrst(struct powerdomain *pwrdm)
 172{
 173        u8 omap2xxx_pwrst;
 174
 175        omap2xxx_pwrst = omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs,
 176                                                       OMAP2_PM_PWSTST,
 177                                                       OMAP_POWERSTATEST_MASK);
 178
 179        return omap2xxx_pwrst_to_common_pwrst(omap2xxx_pwrst);
 180}
 181
 182struct pwrdm_ops omap2_pwrdm_operations = {
 183        .pwrdm_set_next_pwrst   = omap2xxx_pwrdm_set_next_pwrst,
 184        .pwrdm_read_next_pwrst  = omap2xxx_pwrdm_read_next_pwrst,
 185        .pwrdm_read_pwrst       = omap2xxx_pwrdm_read_pwrst,
 186        .pwrdm_set_logic_retst  = omap2_pwrdm_set_logic_retst,
 187        .pwrdm_set_mem_onst     = omap2_pwrdm_set_mem_onst,
 188        .pwrdm_set_mem_retst    = omap2_pwrdm_set_mem_retst,
 189        .pwrdm_read_mem_pwrst   = omap2_pwrdm_read_mem_pwrst,
 190        .pwrdm_read_mem_retst   = omap2_pwrdm_read_mem_retst,
 191        .pwrdm_wait_transition  = omap2_pwrdm_wait_transition,
 192};
 193
 194/*
 195 *
 196 */
 197
 198static struct prm_ll_data omap2xxx_prm_ll_data = {
 199        .read_reset_sources = &omap2xxx_prm_read_reset_sources,
 200};
 201
 202int __init omap2xxx_prm_init(void)
 203{
 204        if (!cpu_is_omap24xx())
 205                return 0;
 206
 207        return prm_register(&omap2xxx_prm_ll_data);
 208}
 209
 210static void __exit omap2xxx_prm_exit(void)
 211{
 212        if (!cpu_is_omap24xx())
 213                return;
 214
 215        /* Should never happen */
 216        WARN(prm_unregister(&omap2xxx_prm_ll_data),
 217             "%s: prm_ll_data function pointer mismatch\n", __func__);
 218}
 219__exitcall(omap2xxx_prm_exit);
 220