mirror of https://gitee.com/openkylin/linux.git
Reimplement the OMAP PRCM I/O chain code. Needed for I/O wakeups to
work correctly. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.12 (GNU/Linux) iQIcBAABAgAGBQJP5I6KAAoJEMePsQ0LvSpLRssP/jARj3CHFK6Y2xSoV8VaVzfV Xa7xBf4nIc5GPTekQWuUMd/dXz+uOGep1fOugMaP1AooCgVN008OL75TwHfsezyL OZxjPjijv6f06/s5o2HfjykFupw6jcHf7nCfoJnBCz5lvjB5nWV/HXPyu5BCmpV8 EwGOBoHtX0pP3kgZYRm9uc7b2eG1hmR7VfMiv0LF2qcRdFnGhsrD2mUGS8HIf4cc IKGqFObvLVdtDO4C3Iiouu/Ak4JphPNuCX2hYS7VoPvv6ccCB1IptI0WEOUpaN/C 60AODSzg6vC+KaDXlV9LEpQNuuxS9Qkrdvdw+ugHG2iQv8V25EpcVSbDHtBeH2cd u9hs3qNtw0dB1BpeQs3GQBiv7Ktj3SON4X7mtEhzAZRtDwFbvib1hXkGB66pf5i/ E3sLOLkTY/BY6PsKRtqmz2YwrpRrcr619d6hHDwK98166f6HfWZV+jFzAgle+ZuW vXVEw/NOtPhdjLEH5gGe5vmg0oNpFU7Li8f5dd3eRB+j4w2JC1OPWntSDAfp6Qq8 GNVZY0rVc0UTQXrj9iCfO6wumwDkNYmnCZp0e5H0RsWLn5w4ibyevWQ44hsNEnfI vEayVteZNnyM7dMqlXcE4L3GKOTPoBLD+frOWgRXBjAqP1o3tZ3LcGveCbVD2/Xs pYgpFOPdClJC0/+mSm0r =AduR -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
9a17d88e05
|
@ -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;
|
||||
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -302,17 +302,60 @@ void omap3xxx_prm_restore_irqen(u32 *saved_mask)
|
|||
OMAP3_PRM_IRQENABLE_MPU_OFFSET);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
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);
|
||||
|
|
|
@ -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
|
||||
|
||||
/*
|
||||
|
|
|
@ -233,10 +233,71 @@ void omap44xx_prm_restore_irqen(u32 *saved_mask)
|
|||
OMAP4_PRM_IRQENABLE_MPU_2_OFFSET);
|
||||
}
|
||||
|
||||
/**
|
||||
* omap44xx_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 waiting for WUCLKOUT to be deasserted.
|
||||
* No return value. XXX Are the final two steps necessary?
|
||||
*/
|
||||
void omap44xx_prm_reconfigure_io_chain(void)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
/* Trigger WUCLKIN enable */
|
||||
omap4_prm_rmw_inst_reg_bits(OMAP4430_WUCLK_CTRL_MASK,
|
||||
OMAP4430_WUCLK_CTRL_MASK,
|
||||
OMAP4430_PRM_DEVICE_INST,
|
||||
OMAP4_PRM_IO_PMCTRL_OFFSET);
|
||||
omap_test_timeout(
|
||||
(((omap4_prm_read_inst_reg(OMAP4430_PRM_DEVICE_INST,
|
||||
OMAP4_PRM_IO_PMCTRL_OFFSET) &
|
||||
OMAP4430_WUCLK_STATUS_MASK) >>
|
||||
OMAP4430_WUCLK_STATUS_SHIFT) == 1),
|
||||
MAX_IOPAD_LATCH_TIME, i);
|
||||
if (i == MAX_IOPAD_LATCH_TIME)
|
||||
pr_warn("PRM: I/O chain clock line assertion timed out\n");
|
||||
|
||||
/* Trigger WUCLKIN disable */
|
||||
omap4_prm_rmw_inst_reg_bits(OMAP4430_WUCLK_CTRL_MASK, 0x0,
|
||||
OMAP4430_PRM_DEVICE_INST,
|
||||
OMAP4_PRM_IO_PMCTRL_OFFSET);
|
||||
omap_test_timeout(
|
||||
(((omap4_prm_read_inst_reg(OMAP4430_PRM_DEVICE_INST,
|
||||
OMAP4_PRM_IO_PMCTRL_OFFSET) &
|
||||
OMAP4430_WUCLK_STATUS_MASK) >>
|
||||
OMAP4430_WUCLK_STATUS_SHIFT) == 0),
|
||||
MAX_IOPAD_LATCH_TIME, i);
|
||||
if (i == MAX_IOPAD_LATCH_TIME)
|
||||
pr_warn("PRM: I/O chain clock line deassertion timed out\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* omap44xx_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
|
||||
* omap44xx_prm_reconfigure_io_chain() must be called. No return value.
|
||||
*/
|
||||
static void __init omap44xx_prm_enable_io_wakeup(void)
|
||||
{
|
||||
omap4_prm_rmw_inst_reg_bits(OMAP4430_GLOBAL_WUEN_MASK,
|
||||
OMAP4430_GLOBAL_WUEN_MASK,
|
||||
OMAP4430_PRM_DEVICE_INST,
|
||||
OMAP4_PRM_IO_PMCTRL_OFFSET);
|
||||
}
|
||||
|
||||
static int __init omap4xxx_prcm_init(void)
|
||||
{
|
||||
if (cpu_is_omap44xx())
|
||||
if (cpu_is_omap44xx()) {
|
||||
omap44xx_prm_enable_io_wakeup();
|
||||
return omap_prcm_register_chain_handler(&omap4_prcm_irq_setup);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
subsys_initcall(omap4xxx_prcm_init);
|
||||
|
|
|
@ -763,6 +763,8 @@ extern u32 omap4_prm_vcvp_read(u8 offset);
|
|||
extern void omap4_prm_vcvp_write(u32 val, u8 offset);
|
||||
extern u32 omap4_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset);
|
||||
|
||||
extern void omap44xx_prm_reconfigure_io_chain(void);
|
||||
|
||||
/* PRM interrupt-related functions */
|
||||
extern void omap44xx_prm_read_pending_irqs(unsigned long *events);
|
||||
extern void omap44xx_prm_ocp_barrier(void);
|
||||
|
|
Loading…
Reference in New Issue