Commit b02b9172 authored by Paul Walmsley's avatar Paul Walmsley Committed by Kevin Hilman

ARM: OMAP3: PM: fix I/O wakeup and I/O chain clock control detection

The way that we detect which OMAP3 chips support I/O wakeup and
software I/O chain clock control is broken.

Currently, I/O wakeup is marked as present for all OMAP3 SoCs other
than the AM3505/3517.  The TI81xx family of SoCs are at present
considered to be OMAP3 SoCs, but don't support I/O wakeup.  To resolve
this, convert the existing blacklist approach to an explicit,
whitelist support, in which only SoCs which are known to support I/O
wakeup are listed.  (At present, this only includes OMAP34xx,
OMAP3503, OMAP3515, OMAP3525, OMAP3530, and OMAP36xx.)

Also, the current code incorrectly detects the presence of a
software-controllable I/O chain clock on several chips that don't
support it.  This results in writes to reserved bitfields, unnecessary
delays, and console messages on kernels running on those chips:

    http://www.spinics.net/lists/linux-omap/msg58735.html

Convert this test to a feature test with a chip-by-chip whitelist.

Thanks to Dave Hylands <dhylands@gmail.com> for reporting this problem
and doing some testing to help isolate the cause.  Thanks to Steve
Sakoman <sakoman@gmail.com> for catching a bug in the first version of
this patch.  Thanks to Russell King <linux@arm.linux.org.uk> for
comments.
Signed-off-by: default avatarPaul Walmsley <paul@pwsan.com>
Cc: Dave Hylands <dhylands@gmail.com>
Cc: Steve Sakoman <sakoman@gmail.com>
Tested-by: default avatarSteve Sakoman <sakoman@gmail.com>
Cc: Russell King - ARM Linux <linux@arm.linux.org.uk>
Signed-off-by: default avatarKevin Hilman <khilman@ti.com>
parent ff2f8e5f
...@@ -201,8 +201,11 @@ static void __init omap3_check_features(void) ...@@ -201,8 +201,11 @@ static void __init omap3_check_features(void)
OMAP3_CHECK_FEATURE(status, ISP); OMAP3_CHECK_FEATURE(status, ISP);
if (cpu_is_omap3630()) if (cpu_is_omap3630())
omap_features |= OMAP3_HAS_192MHZ_CLK; omap_features |= OMAP3_HAS_192MHZ_CLK;
if (!cpu_is_omap3505() && !cpu_is_omap3517()) if (cpu_is_omap3430() || cpu_is_omap3630())
omap_features |= OMAP3_HAS_IO_WAKEUP; omap_features |= OMAP3_HAS_IO_WAKEUP;
if (cpu_is_omap3630() || omap_rev() == OMAP3430_REV_ES3_1 ||
omap_rev() == OMAP3430_REV_ES3_1_2)
omap_features |= OMAP3_HAS_IO_CHAIN_CTRL;
omap_features |= OMAP3_HAS_SDRC; omap_features |= OMAP3_HAS_SDRC;
......
...@@ -99,31 +99,27 @@ static void omap3_enable_io_chain(void) ...@@ -99,31 +99,27 @@ static void omap3_enable_io_chain(void)
{ {
int timeout = 0; int timeout = 0;
if (omap_rev() >= OMAP3430_REV_ES3_1) { omap2_prm_set_mod_reg_bits(OMAP3430_EN_IO_CHAIN_MASK, WKUP_MOD,
omap2_prm_set_mod_reg_bits(OMAP3430_EN_IO_CHAIN_MASK, WKUP_MOD, PM_WKEN);
PM_WKEN); /* Do a readback to assure write has been done */
/* Do a readback to assure write has been done */ omap2_prm_read_mod_reg(WKUP_MOD, PM_WKEN);
omap2_prm_read_mod_reg(WKUP_MOD, PM_WKEN);
while (!(omap2_prm_read_mod_reg(WKUP_MOD, PM_WKEN) &
while (!(omap2_prm_read_mod_reg(WKUP_MOD, PM_WKEN) & OMAP3430_ST_IO_CHAIN_MASK)) {
OMAP3430_ST_IO_CHAIN_MASK)) { timeout++;
timeout++; if (timeout > 1000) {
if (timeout > 1000) { pr_err("Wake up daisy chain activation failed.\n");
printk(KERN_ERR "Wake up daisy chain " return;
"activation failed.\n");
return;
}
omap2_prm_set_mod_reg_bits(OMAP3430_ST_IO_CHAIN_MASK,
WKUP_MOD, PM_WKEN);
} }
omap2_prm_set_mod_reg_bits(OMAP3430_ST_IO_CHAIN_MASK,
WKUP_MOD, PM_WKEN);
} }
} }
static void omap3_disable_io_chain(void) static void omap3_disable_io_chain(void)
{ {
if (omap_rev() >= OMAP3430_REV_ES3_1) omap2_prm_clear_mod_reg_bits(OMAP3430_EN_IO_CHAIN_MASK, WKUP_MOD,
omap2_prm_clear_mod_reg_bits(OMAP3430_EN_IO_CHAIN_MASK, WKUP_MOD, PM_WKEN);
PM_WKEN);
} }
static void omap3_core_save_context(void) static void omap3_core_save_context(void)
...@@ -375,7 +371,8 @@ void omap_sram_idle(void) ...@@ -375,7 +371,8 @@ void omap_sram_idle(void)
(per_next_state < PWRDM_POWER_ON || (per_next_state < PWRDM_POWER_ON ||
core_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); omap2_prm_set_mod_reg_bits(OMAP3430_EN_IO_MASK, WKUP_MOD, PM_WKEN);
omap3_enable_io_chain(); if (omap3_has_io_chain_ctrl())
omap3_enable_io_chain();
} }
/* Block console output in case it is on one of the OMAP UARTs */ /* Block console output in case it is on one of the OMAP UARTs */
...@@ -478,7 +475,8 @@ void omap_sram_idle(void) ...@@ -478,7 +475,8 @@ void omap_sram_idle(void)
core_next_state < PWRDM_POWER_ON)) { core_next_state < PWRDM_POWER_ON)) {
omap2_prm_clear_mod_reg_bits(OMAP3430_EN_IO_MASK, WKUP_MOD, omap2_prm_clear_mod_reg_bits(OMAP3430_EN_IO_MASK, WKUP_MOD,
PM_WKEN); PM_WKEN);
omap3_disable_io_chain(); if (omap3_has_io_chain_ctrl())
omap3_disable_io_chain();
} }
clkdm_allow_idle(mpu_pwrdm->pwrdm_clkdms[0]); clkdm_allow_idle(mpu_pwrdm->pwrdm_clkdms[0]);
...@@ -871,6 +869,9 @@ static int __init omap3_pm_init(void) ...@@ -871,6 +869,9 @@ static int __init omap3_pm_init(void)
if (!cpu_is_omap34xx()) if (!cpu_is_omap34xx())
return -ENODEV; return -ENODEV;
if (!omap3_has_io_chain_ctrl())
pr_warning("PM: no software I/O chain control; some wakeups may be lost\n");
pm_errata_configure(); pm_errata_configure();
/* XXX prcm_setup_regs needs to be before enabling hw /* XXX prcm_setup_regs needs to be before enabling hw
......
...@@ -477,6 +477,13 @@ void omap2_check_revision(void); ...@@ -477,6 +477,13 @@ void omap2_check_revision(void);
/* /*
* Runtime detection of OMAP3 features * Runtime detection of OMAP3 features
*
* OMAP3_HAS_IO_CHAIN_CTRL: Some later members of the OMAP3 chip
* family have OS-level control over the I/O chain clock. This is
* to avoid a window during which wakeups could potentially be lost
* during powerdomain transitions. If this bit is set, it
* indicates that the chip does support OS-level control of this
* feature.
*/ */
extern u32 omap_features; extern u32 omap_features;
...@@ -488,9 +495,10 @@ extern u32 omap_features; ...@@ -488,9 +495,10 @@ extern u32 omap_features;
#define OMAP3_HAS_192MHZ_CLK BIT(5) #define OMAP3_HAS_192MHZ_CLK BIT(5)
#define OMAP3_HAS_IO_WAKEUP BIT(6) #define OMAP3_HAS_IO_WAKEUP BIT(6)
#define OMAP3_HAS_SDRC BIT(7) #define OMAP3_HAS_SDRC BIT(7)
#define OMAP4_HAS_MPU_1GHZ BIT(8) #define OMAP3_HAS_IO_CHAIN_CTRL BIT(8)
#define OMAP4_HAS_MPU_1_2GHZ BIT(9) #define OMAP4_HAS_MPU_1GHZ BIT(9)
#define OMAP4_HAS_MPU_1_5GHZ BIT(10) #define OMAP4_HAS_MPU_1_2GHZ BIT(10)
#define OMAP4_HAS_MPU_1_5GHZ BIT(11)
#define OMAP3_HAS_FEATURE(feat,flag) \ #define OMAP3_HAS_FEATURE(feat,flag) \
...@@ -507,12 +515,11 @@ OMAP3_HAS_FEATURE(isp, ISP) ...@@ -507,12 +515,11 @@ OMAP3_HAS_FEATURE(isp, ISP)
OMAP3_HAS_FEATURE(192mhz_clk, 192MHZ_CLK) OMAP3_HAS_FEATURE(192mhz_clk, 192MHZ_CLK)
OMAP3_HAS_FEATURE(io_wakeup, IO_WAKEUP) OMAP3_HAS_FEATURE(io_wakeup, IO_WAKEUP)
OMAP3_HAS_FEATURE(sdrc, SDRC) OMAP3_HAS_FEATURE(sdrc, SDRC)
OMAP3_HAS_FEATURE(io_chain_ctrl, IO_CHAIN_CTRL)
/* /*
* Runtime detection of OMAP4 features * Runtime detection of OMAP4 features
*/ */
extern u32 omap_features;
#define OMAP4_HAS_FEATURE(feat, flag) \ #define OMAP4_HAS_FEATURE(feat, flag) \
static inline unsigned int omap4_has_ ##feat(void) \ static inline unsigned int omap4_has_ ##feat(void) \
{ \ { \
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment