prm2xxx.c 6.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/*
 * OMAP2xxx PRM module functions
 *
 * Copyright (C) 2010-2012 Texas Instruments, Inc.
 * Copyright (C) 2010 Nokia Corporation
 * Benoît Cousson
 * Paul Walmsley
 * Rajendra Nayak <rnayak@ti.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/irq.h>

#include "powerdomain.h"
22
#include "clockdomain.h"
23 24 25 26
#include "prm2xxx.h"
#include "cm2xxx_3xxx.h"
#include "prm-regbits-24xx.h"

27 28 29 30 31 32 33 34
/*
 * OMAP24xx PM_PWSTCTRL_*.POWERSTATE and PM_PWSTST_*.LASTSTATEENTERED bits -
 * these are reversed from the bits used on OMAP3+
 */
#define OMAP24XX_PWRDM_POWER_ON			0x0
#define OMAP24XX_PWRDM_POWER_RET		0x1
#define OMAP24XX_PWRDM_POWER_OFF		0x3

35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
/*
 * omap2xxx_prm_reset_src_map - map from bits in the PRM_RSTST_WKUP
 *   hardware register (which are specific to the OMAP2xxx SoCs) to
 *   reset source ID bit shifts (which is an OMAP SoC-independent
 *   enumeration)
 */
static struct prm_reset_src_map omap2xxx_prm_reset_src_map[] = {
	{ OMAP_GLOBALCOLD_RST_SHIFT, OMAP_GLOBAL_COLD_RST_SRC_ID_SHIFT },
	{ OMAP_GLOBALWARM_RST_SHIFT, OMAP_GLOBAL_WARM_RST_SRC_ID_SHIFT },
	{ OMAP24XX_SECU_VIOL_RST_SHIFT, OMAP_SECU_VIOL_RST_SRC_ID_SHIFT },
	{ OMAP24XX_MPU_WD_RST_SHIFT, OMAP_MPU_WD_RST_SRC_ID_SHIFT },
	{ OMAP24XX_SECU_WD_RST_SHIFT, OMAP_SECU_WD_RST_SRC_ID_SHIFT },
	{ OMAP24XX_EXTWMPU_RST_SHIFT, OMAP_EXTWARM_RST_SRC_ID_SHIFT },
	{ -1, -1 },
};

/**
 * omap2xxx_prm_read_reset_sources - return the last SoC reset source
 *
 * Return a u32 representing the last reset sources of the SoC.  The
 * returned reset source bits are standardized across OMAP SoCs.
 */
static u32 omap2xxx_prm_read_reset_sources(void)
{
	struct prm_reset_src_map *p;
	u32 r = 0;
	u32 v;

	v = omap2_prm_read_mod_reg(WKUP_MOD, OMAP2_RM_RSTST);

	p = omap2xxx_prm_reset_src_map;
	while (p->reg_shift >= 0 && p->std_shift >= 0) {
		if (v & (1 << p->reg_shift))
			r |= 1 << p->std_shift;
		p++;
	}

	return r;
}

75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
/**
 * omap2xxx_pwrst_to_common_pwrst - convert OMAP2xxx pwrst to common pwrst
 * @omap2xxx_pwrst: OMAP2xxx hardware power state to convert
 *
 * Return the common power state bits corresponding to the OMAP2xxx
 * hardware power state bits @omap2xxx_pwrst, or -EINVAL upon error.
 */
static int omap2xxx_pwrst_to_common_pwrst(u8 omap2xxx_pwrst)
{
	u8 pwrst;

	switch (omap2xxx_pwrst) {
	case OMAP24XX_PWRDM_POWER_OFF:
		pwrst = PWRDM_POWER_OFF;
		break;
	case OMAP24XX_PWRDM_POWER_RET:
		pwrst = PWRDM_POWER_RET;
		break;
	case OMAP24XX_PWRDM_POWER_ON:
		pwrst = PWRDM_POWER_ON;
		break;
	default:
		return -EINVAL;
	}

	return pwrst;
}

103 104 105 106 107 108
/**
 * omap2xxx_prm_dpll_reset - use DPLL reset to reboot the OMAP SoC
 *
 * Set the DPLL reset bit, which should reboot the SoC.  This is the
 * recommended way to restart the SoC.  No return value.
 */
109
static void omap2xxx_prm_dpll_reset(void)
110 111 112 113 114 115 116
{
	omap2_prm_set_mod_reg_bits(OMAP_RST_DPLL3_MASK, WKUP_MOD,
				   OMAP2_RM_RSTCTRL);
	/* OCP barrier */
	omap2_prm_read_mod_reg(WKUP_MOD, OMAP2_RM_RSTCTRL);
}

117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
/**
 * omap2xxx_prm_clear_mod_irqs - clear wakeup status bits for a module
 * @module: PRM module to clear wakeups from
 * @regs: register offset to clear
 * @wkst_mask: wakeup status mask to clear
 *
 * Clears wakeup status bits for a given module, so that the device can
 * re-enter idle.
 */
void omap2xxx_prm_clear_mod_irqs(s16 module, u8 regs, u32 wkst_mask)
{
	u32 wkst;

	wkst = omap2_prm_read_mod_reg(module, regs);
	wkst &= wkst_mask;
	omap2_prm_write_mod_reg(wkst, module, regs);
}

135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
int omap2xxx_clkdm_sleep(struct clockdomain *clkdm)
{
	omap2_prm_set_mod_reg_bits(OMAP24XX_FORCESTATE_MASK,
				   clkdm->pwrdm.ptr->prcm_offs,
				   OMAP2_PM_PWSTCTRL);
	return 0;
}

int omap2xxx_clkdm_wakeup(struct clockdomain *clkdm)
{
	omap2_prm_clear_mod_reg_bits(OMAP24XX_FORCESTATE_MASK,
				     clkdm->pwrdm.ptr->prcm_offs,
				     OMAP2_PM_PWSTCTRL);
	return 0;
}

151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
static int omap2xxx_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst)
{
	u8 omap24xx_pwrst;

	switch (pwrst) {
	case PWRDM_POWER_OFF:
		omap24xx_pwrst = OMAP24XX_PWRDM_POWER_OFF;
		break;
	case PWRDM_POWER_RET:
		omap24xx_pwrst = OMAP24XX_PWRDM_POWER_RET;
		break;
	case PWRDM_POWER_ON:
		omap24xx_pwrst = OMAP24XX_PWRDM_POWER_ON;
		break;
	default:
		return -EINVAL;
	}

	omap2_prm_rmw_mod_reg_bits(OMAP_POWERSTATE_MASK,
				   (omap24xx_pwrst << OMAP_POWERSTATE_SHIFT),
				   pwrdm->prcm_offs, OMAP2_PM_PWSTCTRL);
	return 0;
}

static int omap2xxx_pwrdm_read_next_pwrst(struct powerdomain *pwrdm)
{
	u8 omap2xxx_pwrst;

	omap2xxx_pwrst = omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs,
						       OMAP2_PM_PWSTCTRL,
						       OMAP_POWERSTATE_MASK);

	return omap2xxx_pwrst_to_common_pwrst(omap2xxx_pwrst);
}

static int omap2xxx_pwrdm_read_pwrst(struct powerdomain *pwrdm)
{
	u8 omap2xxx_pwrst;

	omap2xxx_pwrst = omap2_prm_read_mod_bits_shift(pwrdm->prcm_offs,
						       OMAP2_PM_PWSTST,
						       OMAP_POWERSTATEST_MASK);

	return omap2xxx_pwrst_to_common_pwrst(omap2xxx_pwrst);
}

197
struct pwrdm_ops omap2_pwrdm_operations = {
198 199 200
	.pwrdm_set_next_pwrst	= omap2xxx_pwrdm_set_next_pwrst,
	.pwrdm_read_next_pwrst	= omap2xxx_pwrdm_read_next_pwrst,
	.pwrdm_read_pwrst	= omap2xxx_pwrdm_read_pwrst,
201 202 203 204 205 206 207
	.pwrdm_set_logic_retst	= omap2_pwrdm_set_logic_retst,
	.pwrdm_set_mem_onst	= omap2_pwrdm_set_mem_onst,
	.pwrdm_set_mem_retst	= omap2_pwrdm_set_mem_retst,
	.pwrdm_read_mem_pwrst	= omap2_pwrdm_read_mem_pwrst,
	.pwrdm_read_mem_retst	= omap2_pwrdm_read_mem_retst,
	.pwrdm_wait_transition	= omap2_pwrdm_wait_transition,
};
208 209 210 211 212 213 214

/*
 *
 */

static struct prm_ll_data omap2xxx_prm_ll_data = {
	.read_reset_sources = &omap2xxx_prm_read_reset_sources,
215
	.assert_hardreset = &omap2_prm_assert_hardreset,
216
	.deassert_hardreset = &omap2_prm_deassert_hardreset,
217
	.is_hardreset_asserted = &omap2_prm_is_hardreset_asserted,
218
	.reset_system = &omap2xxx_prm_dpll_reset,
219 220
};

221
int __init omap2xxx_prm_init(void)
222 223 224 225 226 227
{
	return prm_register(&omap2xxx_prm_ll_data);
}

static void __exit omap2xxx_prm_exit(void)
{
228
	prm_unregister(&omap2xxx_prm_ll_data);
229 230
}
__exitcall(omap2xxx_prm_exit);