Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9a17d88e authored by Tony Lindgren's avatar Tony Lindgren
Browse files

Merge tag 'omap-devel-c-for-3.6' of...

Merge tag 'omap-devel-c-for-3.6' of git://git.kernel.org/pub/scm/linux/kernel/git/pjw/omap-pending into devel-pm

Reimplement the OMAP PRCM I/O chain code.  Needed for I/O wakeups to
work correctly.

Conflicts:
	arch/arm/mach-omap2/prm2xxx_3xxx.c
parents 6b16351a fafcdd53
Loading
Loading
Loading
Loading
+36 −2
Original line number Diff line number Diff line
@@ -153,6 +153,7 @@
#include "prm44xx.h"
#include "prminst44xx.h"
#include "mux.h"
#include "pm.h"

/* Maximum microseconds to wait for OMAP module to softreset */
#define MAX_MODULE_SOFTRESET_WAIT	10000
@@ -172,6 +173,9 @@ static LIST_HEAD(omap_hwmod_list);
/* mpu_oh: used to add/remove MPU initiator from sleepdep list */
static struct omap_hwmod *mpu_oh;

/* io_chain_lock: used to serialize reconfigurations of the I/O chain */
static DEFINE_SPINLOCK(io_chain_lock);

/*
 * linkspace: ptr to a buffer that struct omap_hwmod_link records are
 * allocated from - used to reduce the number of small memory
@@ -1737,6 +1741,32 @@ static int _reset(struct omap_hwmod *oh)
	return r;
}

/**
 * _reconfigure_io_chain - clear any I/O chain wakeups and reconfigure chain
 *
 * Call the appropriate PRM function to clear any logged I/O chain
 * wakeups and to reconfigure the chain.  This apparently needs to be
 * done upon every mux change.  Since hwmods can be concurrently
 * enabled and idled, hold a spinlock around the I/O chain
 * reconfiguration sequence.  No return value.
 *
 * XXX When the PRM code is moved to drivers, this function can be removed,
 * as the PRM infrastructure should abstract this.
 */
static void _reconfigure_io_chain(void)
{
	unsigned long flags;

	spin_lock_irqsave(&io_chain_lock, flags);

	if (cpu_is_omap34xx() && omap3_has_io_chain_ctrl())
		omap3xxx_prm_reconfigure_io_chain();
	else if (cpu_is_omap44xx())
		omap44xx_prm_reconfigure_io_chain();

	spin_unlock_irqrestore(&io_chain_lock, flags);
}

/**
 * _enable - enable an omap_hwmod
 * @oh: struct omap_hwmod *
@@ -1793,8 +1823,10 @@ static int _enable(struct omap_hwmod *oh)
	/* Mux pins for device runtime if populated */
	if (oh->mux && (!oh->mux->enabled ||
			((oh->_state == _HWMOD_STATE_IDLE) &&
			 oh->mux->pads_dynamic)))
			 oh->mux->pads_dynamic))) {
		omap_hwmod_mux(oh->mux, _HWMOD_STATE_ENABLED);
		_reconfigure_io_chain();
	}

	_add_initiator_dep(oh, mpu_oh);

@@ -1883,8 +1915,10 @@ static int _idle(struct omap_hwmod *oh)
		clkdm_hwmod_disable(oh->clkdm, oh);

	/* Mux pins for device idle if populated */
	if (oh->mux && oh->mux->pads_dynamic)
	if (oh->mux && oh->mux->pads_dynamic) {
		omap_hwmod_mux(oh->mux, _HWMOD_STATE_IDLE);
		_reconfigure_io_chain();
	}

	oh->_state = _HWMOD_STATE_IDLE;

+0 −44
Original line number Diff line number Diff line
@@ -72,33 +72,6 @@ static struct powerdomain *mpu_pwrdm, *neon_pwrdm;
static struct powerdomain *core_pwrdm, *per_pwrdm;
static struct powerdomain *cam_pwrdm;

static void omap3_enable_io_chain(void)
{
	int timeout = 0;

	omap2_prm_set_mod_reg_bits(OMAP3430_EN_IO_CHAIN_MASK, WKUP_MOD,
				   PM_WKEN);
	/* Do a readback to assure write has been done */
	omap2_prm_read_mod_reg(WKUP_MOD, PM_WKEN);

	while (!(omap2_prm_read_mod_reg(WKUP_MOD, PM_WKEN) &
		 OMAP3430_ST_IO_CHAIN_MASK)) {
		timeout++;
		if (timeout > 1000) {
			pr_err("Wake up daisy chain activation failed.\n");
			return;
		}
		omap2_prm_set_mod_reg_bits(OMAP3430_ST_IO_CHAIN_MASK,
					   WKUP_MOD, PM_WKEN);
	}
}

static void omap3_disable_io_chain(void)
{
	omap2_prm_clear_mod_reg_bits(OMAP3430_EN_IO_CHAIN_MASK, WKUP_MOD,
				     PM_WKEN);
}

static void omap3_core_save_context(void)
{
	omap3_ctrl_save_padconf();
@@ -299,13 +272,6 @@ void omap_sram_idle(void)
	/* Enable IO-PAD and IO-CHAIN wakeups */
	per_next_state = pwrdm_read_next_pwrst(per_pwrdm);
	core_next_state = pwrdm_read_next_pwrst(core_pwrdm);
	if (omap3_has_io_wakeup() &&
	    (per_next_state < PWRDM_POWER_ON ||
	     core_next_state < PWRDM_POWER_ON)) {
		omap2_prm_set_mod_reg_bits(OMAP3430_EN_IO_MASK, WKUP_MOD, PM_WKEN);
		if (omap3_has_io_chain_ctrl())
			omap3_enable_io_chain();
	}

	pwrdm_pre_transition();

@@ -378,16 +344,6 @@ void omap_sram_idle(void)
	if (per_next_state < PWRDM_POWER_ON)
		omap2_gpio_resume_after_idle();

	/* Disable IO-PAD and IO-CHAIN wakeup */
	if (omap3_has_io_wakeup() &&
	    (per_next_state < PWRDM_POWER_ON ||
	     core_next_state < PWRDM_POWER_ON)) {
		omap2_prm_clear_mod_reg_bits(OMAP3430_EN_IO_MASK, WKUP_MOD,
					     PM_WKEN);
		if (omap3_has_io_chain_ctrl())
			omap3_disable_io_chain();
	}

	clkdm_allow_idle(mpu_pwrdm->pwrdm_clkdms[0]);
}

+8 −0
Original line number Diff line number Diff line
@@ -410,6 +410,14 @@
 */
#define MAX_MODULE_HARDRESET_WAIT		10000

/*
 * Maximum time(us) it takes to output the signal WUCLKOUT of the last
 * pad of the I/O ring after asserting WUCLKIN high.  Tero measured
 * the actual time at 7 to 8 microseconds on OMAP3 and 2 to 4
 * microseconds on OMAP4, so this timeout may be too high.
 */
#define MAX_IOPAD_LATCH_TIME			100

# ifndef __ASSEMBLER__
extern void __iomem *prm_base;
extern void __iomem *cm_base;
+50 −7
Original line number Diff line number Diff line
@@ -302,17 +302,60 @@ void omap3xxx_prm_restore_irqen(u32 *saved_mask)
				OMAP3_PRM_IRQENABLE_MPU_OFFSET);
}

static int __init omap3xxx_prcm_init(void)
/**
 * omap3xxx_prm_reconfigure_io_chain - clear latches and reconfigure I/O chain
 *
 * Clear any previously-latched I/O wakeup events and ensure that the
 * I/O wakeup gates are aligned with the current mux settings.  Works
 * by asserting WUCLKIN, waiting for WUCLKOUT to be asserted, and then
 * deasserting WUCLKIN and clearing the ST_IO_CHAIN WKST bit.  No
 * return value.
 */
void omap3xxx_prm_reconfigure_io_chain(void)
{
	int i = 0;

	omap2_prm_set_mod_reg_bits(OMAP3430_EN_IO_CHAIN_MASK, WKUP_MOD,
				   PM_WKEN);

	omap_test_timeout(omap2_prm_read_mod_reg(WKUP_MOD, PM_WKST) &
			  OMAP3430_ST_IO_CHAIN_MASK,
			  MAX_IOPAD_LATCH_TIME, i);
	if (i == MAX_IOPAD_LATCH_TIME)
		pr_warn("PRM: I/O chain clock line assertion timed out\n");

	omap2_prm_clear_mod_reg_bits(OMAP3430_EN_IO_CHAIN_MASK, WKUP_MOD,
				     PM_WKEN);

	omap2_prm_set_mod_reg_bits(OMAP3430_ST_IO_CHAIN_MASK, WKUP_MOD,
				   PM_WKST);

	omap2_prm_read_mod_reg(WKUP_MOD, PM_WKST);
}

/**
 * omap3xxx_prm_enable_io_wakeup - enable wakeup events from I/O wakeup latches
 *
 * Activates the I/O wakeup event latches and allows events logged by
 * those latches to signal a wakeup event to the PRCM.  For I/O
 * wakeups to occur, WAKEUPENABLE bits must be set in the pad mux
 * registers, and omap3xxx_prm_reconfigure_io_chain() must be called.
 * No return value.
 */
static void __init omap3xxx_prm_enable_io_wakeup(void)
{
	int ret = 0;
	if (omap3_has_io_wakeup())
		omap2_prm_set_mod_reg_bits(OMAP3430_EN_IO_MASK, WKUP_MOD,
					   PM_WKEN);
}

static int __init omap3xxx_prcm_init(void)
{
	if (cpu_is_omap34xx()) {
		ret = omap_prcm_register_chain_handler(&omap3_prcm_irq_setup);
		if (!ret)
			irq_set_status_flags(omap_prcm_event_to_irq("io"),
					     IRQ_NOAUTOEN);
		omap3xxx_prm_enable_io_wakeup();
		return omap_prcm_register_chain_handler(&omap3_prcm_irq_setup);
	}

	return ret;
	return 0;
}
subsys_initcall(omap3xxx_prcm_init);
+4 −2
Original line number Diff line number Diff line
@@ -303,6 +303,8 @@ extern int omap2_prm_is_hardreset_asserted(s16 prm_mod, u8 shift);
extern int omap2_prm_assert_hardreset(s16 prm_mod, u8 shift);
extern int omap2_prm_deassert_hardreset(s16 prm_mod, u8 rst_shift, u8 st_shift);

#endif	/* CONFIG_ARCH_OMAP4 */

/* OMAP3-specific VP functions */
u32 omap3_prm_vp_check_txdone(u8 vp_id);
void omap3_prm_vp_clear_txdone(u8 vp_id);
@@ -315,14 +317,14 @@ extern u32 omap3_prm_vcvp_read(u8 offset);
extern void omap3_prm_vcvp_write(u32 val, u8 offset);
extern u32 omap3_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset);

extern void omap3xxx_prm_reconfigure_io_chain(void);

/* PRM interrupt-related functions */
extern void omap3xxx_prm_read_pending_irqs(unsigned long *events);
extern void omap3xxx_prm_ocp_barrier(void);
extern void omap3xxx_prm_save_and_clear_irqen(u32 *saved_mask);
extern void omap3xxx_prm_restore_irqen(u32 *saved_mask);

#endif	/* CONFIG_ARCH_OMAP4 */

#endif

/*
Loading