From cfefe3c683e0d14c9ce3aeb883c55c7f30c20183 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Sat, 9 Feb 2008 04:12:37 +0800 Subject: [Blackfin] arch: hook up set_irq_wake in Blackfin's irq code - Add support for irq_wake on system and gpio interrupts - Remove outdated kernel options - Add option to select default PM mode - Fix various places where SIC_IWRx was only handled partially Signed-off-by: Michael Hennerich Signed-off-by: Bryan Wu --- arch/blackfin/mach-common/dpmc.S | 32 +++++++- arch/blackfin/mach-common/ints-priority.c | 126 ++++++++++++++++++++++++++++-- arch/blackfin/mach-common/pm.c | 44 ++++------- 3 files changed, 168 insertions(+), 34 deletions(-) (limited to 'arch/blackfin/mach-common') diff --git a/arch/blackfin/mach-common/dpmc.S b/arch/blackfin/mach-common/dpmc.S index b82c096e198..b80ddd8b232 100644 --- a/arch/blackfin/mach-common/dpmc.S +++ b/arch/blackfin/mach-common/dpmc.S @@ -191,6 +191,9 @@ ENTRY(_sleep_mode) call _test_pll_locked; R0 = IWR_ENABLE(0); + R1 = IWR_DISABLE_ALL; + R2 = IWR_DISABLE_ALL; + call _set_sic_iwr; P0.H = hi(PLL_CTL); @@ -237,6 +240,10 @@ ENTRY(_deep_sleep) CLI R4; + R0 = IWR_ENABLE(0); + R1 = IWR_DISABLE_ALL; + R2 = IWR_DISABLE_ALL; + call _set_sic_iwr; call _set_dram_srfs; @@ -261,6 +268,9 @@ ENTRY(_deep_sleep) call _test_pll_locked; R0 = IWR_ENABLE(0); + R1 = IWR_DISABLE_ALL; + R2 = IWR_DISABLE_ALL; + call _set_sic_iwr; P0.H = hi(PLL_CTL); @@ -286,7 +296,13 @@ ENTRY(_sleep_deeper) CLI R4; P3 = R0; + P4 = R1; + P5 = R2; + R0 = IWR_ENABLE(0); + R1 = IWR_DISABLE_ALL; + R2 = IWR_DISABLE_ALL; + call _set_sic_iwr; call _set_dram_srfs; /* Set SDRAM Self Refresh */ @@ -327,6 +343,8 @@ ENTRY(_sleep_deeper) call _test_pll_locked; R0 = P3; + R1 = P4; + R3 = P5; call _set_sic_iwr; /* Set Awake from IDLE */ P0.H = hi(PLL_CTL); @@ -340,6 +358,9 @@ ENTRY(_sleep_deeper) call _test_pll_locked; R0 = IWR_ENABLE(0); + R1 = IWR_DISABLE_ALL; + R2 = IWR_DISABLE_ALL; + call _set_sic_iwr; /* Set Awake from IDLE PLL */ P0.H = hi(VR_CTL); @@ -417,14 +438,23 @@ ENTRY(_unset_dram_srfs) RTS; ENTRY(_set_sic_iwr) -#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) +#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) || defined(CONFIG_BF561) P0.H = hi(SIC_IWR0); P0.L = lo(SIC_IWR0); + P1.H = hi(SIC_IWR1); + P1.L = lo(SIC_IWR1); + [P1] = R1; +#if defined(CONFIG_BF54x) + P1.H = hi(SIC_IWR2); + P1.L = lo(SIC_IWR2); + [P1] = R2; +#endif #else P0.H = hi(SIC_IWR); P0.L = lo(SIC_IWR); #endif [P0] = R0; + SSYNC; RTS; diff --git a/arch/blackfin/mach-common/ints-priority.c b/arch/blackfin/mach-common/ints-priority.c index 166dbba0c39..81d00183ae9 100644 --- a/arch/blackfin/mach-common/ints-priority.c +++ b/arch/blackfin/mach-common/ints-priority.c @@ -1,5 +1,5 @@ /* - * File: arch/blackfin/mach-common/ints-priority-sc.c + * File: arch/blackfin/mach-common/ints-priority.c * Based on: * Author: * @@ -13,7 +13,7 @@ * 2002 Arcturus Networks Inc. MaTed * 2003 Metrowerks/Motorola * 2003 Bas Vermeulen - * Copyright 2004-2007 Analog Devices Inc. + * Copyright 2004-2008 Analog Devices Inc. * * Bugs: Enter bugs at http://blackfin.uclinux.org/ * @@ -69,6 +69,10 @@ unsigned long irq_flags = 0x1f; /* The number of spurious interrupts */ atomic_t num_spurious; +#ifdef CONFIG_PM +unsigned long bfin_sic_iwr[3]; /* Up to 3 SIC_IWRx registers */ +#endif + struct ivgx { /* irq number for request_irq, available in mach-bf533/irq.h */ unsigned int irqno; @@ -178,6 +182,27 @@ static void bfin_internal_unmask_irq(unsigned int irq) SSYNC(); } +#ifdef CONFIG_PM +int bfin_internal_set_wake(unsigned int irq, unsigned int state) +{ + unsigned bank, bit; + unsigned long flags; + bank = (irq - (IRQ_CORETMR + 1)) / 32; + bit = (irq - (IRQ_CORETMR + 1)) % 32; + + local_irq_save(flags); + + if (state) + bfin_sic_iwr[bank] |= (1 << bit); + else + bfin_sic_iwr[bank] &= ~(1 << bit); + + local_irq_restore(flags); + + return 0; +} +#endif + static struct irq_chip bfin_core_irqchip = { .ack = ack_noop, .mask = bfin_core_mask_irq, @@ -188,6 +213,9 @@ static struct irq_chip bfin_internal_irqchip = { .ack = ack_noop, .mask = bfin_internal_mask_irq, .unmask = bfin_internal_unmask_irq, +#ifdef CONFIG_PM + .set_wake = bfin_internal_set_wake, +#endif }; #ifdef BF537_GENERIC_ERROR_INT_DEMUX @@ -434,6 +462,20 @@ static int bfin_gpio_irq_type(unsigned int irq, unsigned int type) return 0; } +#ifdef CONFIG_PM +int bfin_gpio_set_wake(unsigned int irq, unsigned int state) +{ + unsigned gpio = irq_to_gpio(irq); + + if (state) + gpio_pm_wakeup_request(gpio, PM_WAKE_IGNORE); + else + gpio_pm_wakeup_free(gpio); + + return 0; +} +#endif + static struct irq_chip bfin_gpio_irqchip = { .ack = bfin_gpio_ack_irq, .mask = bfin_gpio_mask_irq, @@ -441,7 +483,10 @@ static struct irq_chip bfin_gpio_irqchip = { .unmask = bfin_gpio_unmask_irq, .set_type = bfin_gpio_irq_type, .startup = bfin_gpio_irq_startup, - .shutdown = bfin_gpio_irq_shutdown + .shutdown = bfin_gpio_irq_shutdown, +#ifdef CONFIG_PM + .set_wake = bfin_gpio_set_wake, +#endif }; static void bfin_demux_gpio_irq(unsigned int inta_irq, @@ -487,7 +532,7 @@ static void bfin_demux_gpio_irq(unsigned int inta_irq, } if (search) { - for (i = 0; i < MAX_BLACKFIN_GPIOS; i += 16) { + for (i = 0; i < MAX_BLACKFIN_GPIOS; i += GPIO_BANKSIZE) { irq += i; mask = get_gpiop_data(i) & @@ -763,6 +808,74 @@ static int bfin_gpio_irq_type(unsigned int irq, unsigned int type) return 0; } +#ifdef CONFIG_PM +u32 pint_saved_masks[NR_PINT_SYS_IRQS]; +u32 pint_wakeup_masks[NR_PINT_SYS_IRQS]; + +int bfin_gpio_set_wake(unsigned int irq, unsigned int state) +{ + u32 pint_irq; + u8 pint_val = irq2pint_lut[irq - SYS_IRQS]; + u32 bank = PINT_2_BANK(pint_val); + u32 pintbit = PINT_BIT(pint_val); + + switch (bank) { + case 0: + pint_irq = IRQ_PINT0; + break; + case 2: + pint_irq = IRQ_PINT2; + break; + case 3: + pint_irq = IRQ_PINT3; + break; + case 1: + pint_irq = IRQ_PINT1; + break; + default: + return -EINVAL; + } + + bfin_internal_set_wake(pint_irq, state); + + if (state) + pint_wakeup_masks[bank] |= pintbit; + else + pint_wakeup_masks[bank] &= ~pintbit; + + return 0; +} + +u32 bfin_pm_setup(void) +{ + u32 val, i; + + for (i = 0; i < NR_PINT_SYS_IRQS; i++) { + val = pint[i]->mask_clear; + pint_saved_masks[i] = val; + if (val ^ pint_wakeup_masks[i]) { + pint[i]->mask_clear = val; + pint[i]->mask_set = pint_wakeup_masks[i]; + } + } + + return 0; +} + +void bfin_pm_restore(void) +{ + u32 i, val; + + for (i = 0; i < NR_PINT_SYS_IRQS; i++) { + val = pint_saved_masks[i]; + if (val ^ pint_wakeup_masks[i]) { + pint[i]->mask_clear = pint[i]->mask_clear; + pint[i]->mask_set = val; + } + } +} +#endif + static struct irq_chip bfin_gpio_irqchip = { .ack = bfin_gpio_ack_irq, .mask = bfin_gpio_mask_irq, @@ -770,7 +883,10 @@ static struct irq_chip bfin_gpio_irqchip = { .unmask = bfin_gpio_unmask_irq, .set_type = bfin_gpio_irq_type, .startup = bfin_gpio_irq_startup, - .shutdown = bfin_gpio_irq_shutdown + .shutdown = bfin_gpio_irq_shutdown, +#ifdef CONFIG_PM + .set_wake = bfin_gpio_set_wake, +#endif }; static void bfin_demux_gpio_irq(unsigned int inta_irq, diff --git a/arch/blackfin/mach-common/pm.c b/arch/blackfin/mach-common/pm.c index 81930f7d06f..0be805ca423 100644 --- a/arch/blackfin/mach-common/pm.c +++ b/arch/blackfin/mach-common/pm.c @@ -4,7 +4,7 @@ * Author: Cliff Brake Copyright (c) 2001 * * Created: 2001 - * Description: Power management for the bfin + * Description: Blackfin power management * * Modified: Nicolas Pitre - PXA250 support * Copyright (c) 2002 Monta Vista Software, Inc. @@ -12,7 +12,7 @@ * Copyright (c) 2002 Monta Vista Software, Inc. * Dirk Behme - OMAP1510/1610 * Copyright 2004 - * Copyright 2004-2006 Analog Devices Inc. + * Copyright 2004-2008 Analog Devices Inc. * * Bugs: Enter bugs at http://blackfin.uclinux.org/ * @@ -67,42 +67,30 @@ void bfin_pm_suspend_standby_enter(void) gpio_pm_wakeup_request(CONFIG_PM_WAKEUP_GPIO_NUMBER, WAKEUP_TYPE); #endif -#if defined(CONFIG_PM_WAKEUP_BY_GPIO) || defined(CONFIG_PM_WAKEUP_GPIO_API) - { - u32 flags; + u32 flags; - local_irq_save(flags); + local_irq_save(flags); + bfin_pm_setup(); - sleep_deeper(gpio_pm_setup()); /*Goto Sleep*/ - - gpio_pm_restore(); - -#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) - bfin_write_SIC_IWR0(IWR_ENABLE_ALL); - bfin_write_SIC_IWR1(IWR_ENABLE_ALL); -# ifdef CONFIG_BF54x - bfin_write_SIC_IWR2(IWR_ENABLE_ALL); -# endif +#ifdef CONFIG_PM_BFIN_SLEEP_DEEPER + sleep_deeper(bfin_sic_iwr[0], bfin_sic_iwr[1], bfin_sic_iwr[2]); #else - bfin_write_SIC_IWR(IWR_ENABLE_ALL); + sleep_mode(bfin_sic_iwr[0], bfin_sic_iwr[1], bfin_sic_iwr[2]); #endif - local_irq_restore(flags); - } -#endif + bfin_pm_restore(); -#if defined(CONFIG_PM_WAKEUP_GPIO_BY_SIC_IWR) - sleep_deeper(CONFIG_PM_WAKEUP_SIC_IWR); -# if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) +#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) || defined(CONFIG_BF561) bfin_write_SIC_IWR0(IWR_ENABLE_ALL); bfin_write_SIC_IWR1(IWR_ENABLE_ALL); -# ifdef CONFIG_BF54x +# ifdef CONFIG_BF54x bfin_write_SIC_IWR2(IWR_ENABLE_ALL); -# endif -# else - bfin_write_SIC_IWR(IWR_ENABLE_ALL); # endif -#endif /* CONFIG_PM_WAKEUP_GPIO_BY_SIC_IWR */ +#else + bfin_write_SIC_IWR(IWR_ENABLE_ALL); +#endif + + local_irq_restore(flags); } /* -- cgit v1.2.3