[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 <michael.hennerich@analog.com>
Signed-off-by: Bryan Wu <bryan.wu@analog.com>
This commit is contained in:
Michael Hennerich 2008-02-09 04:12:37 +08:00 committed by Bryan Wu
parent 2c4f829b0c
commit cfefe3c683
8 changed files with 216 additions and 71 deletions

View File

@ -904,29 +904,38 @@ config ARCH_SUSPEND_POSSIBLE
depends on !SMP
choice
prompt "Select PM Wakeup Event Source"
default PM_WAKEUP_GPIO_BY_SIC_IWR
prompt "Default Power Saving Mode"
depends on PM
default PM_BFIN_SLEEP_DEEPER
config PM_BFIN_SLEEP_DEEPER
bool "Sleep Deeper"
help
If you have a GPIO already configured as input with the corresponding PORTx_MASK
bit set - "Specify Wakeup Event by SIC_IWR value"
config PM_WAKEUP_GPIO_BY_SIC_IWR
bool "Specify Wakeup Event by SIC_IWR value"
config PM_WAKEUP_BY_GPIO
bool "Cause Wakeup Event by GPIO"
config PM_WAKEUP_GPIO_API
bool "Configure Wakeup Event by PM GPIO API"
Sleep "Deeper" Mode (High Power Savings) - This mode reduces dynamic
power dissipation by disabling the clock to the processor core (CCLK).
Furthermore, Standby sets the internal power supply voltage (VDDINT)
to 0.85 V to provide the greatest power savings, while preserving the
processor state.
The PLL and system clock (SCLK) continue to operate at a very low
frequency of about 3.3 MHz. To preserve data integrity in the SDRAM,
the SDRAM is put into Self Refresh Mode. Typically an external event
such as GPIO interrupt or RTC activity wakes up the processor.
Various Peripherals such as UART, SPORT, PPI may not function as
normal during Sleep Deeper, due to the reduced SCLK frequency.
When in the sleep mode, system DMA access to L1 memory is not supported.
config PM_BFIN_SLEEP
bool "Sleep"
help
Sleep Mode (High Power Savings) - The sleep mode reduces power
dissipation by disabling the clock to the processor core (CCLK).
The PLL and system clock (SCLK), however, continue to operate in
this mode. Typically an external event or RTC activity will wake
up the processor. When in the sleep mode,
system DMA access to L1 memory is not supported.
endchoice
config PM_WAKEUP_SIC_IWR
hex "Wakeup Events (SIC_IWR)"
depends on PM_WAKEUP_GPIO_BY_SIC_IWR
default 0x8 if (BF537 || BF536 || BF534)
default 0x80 if (BF533 || BF532 || BF531)
default 0x80 if (BF54x)
default 0x80 if (BF52x)
config PM_WAKEUP_BY_GPIO
bool "Cause Wakeup Event by GPIO"
config PM_WAKEUP_GPIO_NUMBER
int "Wakeup GPIO number"

View File

@ -186,7 +186,7 @@ static struct str_ident {
char name[RESOURCE_LABEL_SIZE];
} str_ident[MAX_RESOURCES];
#ifdef CONFIG_PM
#if defined(CONFIG_PM) && !defined(CONFIG_BF54x)
static unsigned short wakeup_map[gpio_bank(MAX_BLACKFIN_GPIOS)];
static unsigned char wakeup_flags_map[MAX_BLACKFIN_GPIOS];
static struct gpio_port_s gpio_bank_saved[gpio_bank(MAX_BLACKFIN_GPIOS)];
@ -696,9 +696,8 @@ static int bfin_gpio_wakeup_type(unsigned gpio, unsigned char type)
return 0;
}
u32 gpio_pm_setup(void)
u32 bfin_pm_setup(void)
{
u32 sic_iwr = 0;
u16 bank, mask, i, gpio;
for (i = 0; i < MAX_BLACKFIN_GPIOS; i += GPIO_BANKSIZE) {
@ -723,7 +722,8 @@ u32 gpio_pm_setup(void)
gpio = i;
while (mask) {
if (mask & 1) {
if ((mask & 1) && (wakeup_flags_map[gpio] !=
PM_WAKE_IGNORE)) {
reserved_gpio_map[gpio_bank(gpio)] |=
gpio_bit(gpio);
bfin_gpio_wakeup_type(gpio,
@ -734,21 +734,17 @@ u32 gpio_pm_setup(void)
mask >>= 1;
}
sic_iwr |= 1 <<
(sic_iwr_irqs[bank] - (IRQ_CORETMR + 1));
bfin_internal_set_wake(sic_iwr_irqs[bank], 1);
gpio_bankb[bank]->maskb_set = wakeup_map[gpio_bank(i)];
}
}
AWA_DUMMY_READ(maskb_set);
if (sic_iwr)
return sic_iwr;
else
return IWR_ENABLE_ALL;
return 0;
}
void gpio_pm_restore(void)
void bfin_pm_restore(void)
{
u16 bank, mask, i;
@ -768,7 +764,7 @@ void gpio_pm_restore(void)
reserved_gpio_map[bank] =
gpio_bank_saved[bank].reserved;
bfin_internal_set_wake(sic_iwr_irqs[bank], 0);
}
gpio_bankb[bank]->maskb = gpio_bank_saved[bank].maskb;

View File

@ -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;

View File

@ -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 <mated@sympatico.ca>
* 2003 Metrowerks/Motorola
* 2003 Bas Vermeulen <bas@buyways.nl>
* 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,

View File

@ -4,7 +4,7 @@
* Author: Cliff Brake <cbrake@accelent.com> 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 <dirk.behme@de.bosch.com> - 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,17 +67,20 @@ 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;
local_irq_save(flags);
bfin_pm_setup();
sleep_deeper(gpio_pm_setup()); /*Goto Sleep*/
#ifdef CONFIG_PM_BFIN_SLEEP_DEEPER
sleep_deeper(bfin_sic_iwr[0], bfin_sic_iwr[1], bfin_sic_iwr[2]);
#else
sleep_mode(bfin_sic_iwr[0], bfin_sic_iwr[1], bfin_sic_iwr[2]);
#endif
gpio_pm_restore();
bfin_pm_restore();
#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
@ -89,21 +92,6 @@ void bfin_pm_suspend_standby_enter(void)
local_irq_restore(flags);
}
#endif
#if defined(CONFIG_PM_WAKEUP_GPIO_BY_SIC_IWR)
sleep_deeper(CONFIG_PM_WAKEUP_SIC_IWR);
# 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
# else
bfin_write_SIC_IWR(IWR_ENABLE_ALL);
# endif
#endif /* CONFIG_PM_WAKEUP_GPIO_BY_SIC_IWR */
}
/*
* bfin_pm_valid - Tell the PM core that we only support the standby sleep

View File

@ -70,6 +70,7 @@ extern void program_IAR(void);
extern void evt14_softirq(void);
extern asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs);
extern void bfin_gpio_interrupt_setup(int irq, int irq_pfx, int type);
extern int bfin_internal_set_wake(unsigned int irq, unsigned int state);
extern asmlinkage void finish_atomic_sections (struct pt_regs *regs);
extern char fixed_code_start;
@ -121,6 +122,7 @@ extern unsigned long dpdt_swapcount_table[];
extern unsigned long table_start, table_end;
extern unsigned long bfin_sic_iwr[];
extern u16 _bfin_swrst; /* shadow for Software Reset Register (SWRST) */
extern struct file_operations dpmc_fops;
extern char _start;

View File

@ -53,10 +53,10 @@ unsigned long get_pll_status(void);
void change_baud(int baud);
void fullon_mode(void);
void active_mode(void);
void sleep_mode(u32 sic_iwr);
void deep_sleep(u32 sic_iwr);
void hibernate_mode(u32 sic_iwr);
void sleep_deeper(u32 sic_iwr);
void sleep_mode(u32 sic_iwr0, u32 sic_iwr1, u32 sic_iwr2);
void deep_sleep(u32 sic_iwr0, u32 sic_iwr1, u32 sic_iwr2);
void hibernate_mode(u32 sic_iwr0, u32 sic_iwr1, u32 sic_iwr2);
void sleep_deeper(u32 sic_iwr0, u32 sic_iwr1, u32 sic_iwr2);
void program_wdog_timer(unsigned long);
void unmask_wdog_wakeup_evt(void);
void clear_wdog_wakeup_evt(void);

View File

@ -376,16 +376,19 @@ struct gpio_port_t {
#endif
#ifdef CONFIG_PM
unsigned int bfin_pm_setup(void);
void bfin_pm_restore(void);
#ifndef CONFIG_BF54x
#define PM_WAKE_RISING 0x1
#define PM_WAKE_FALLING 0x2
#define PM_WAKE_HIGH 0x4
#define PM_WAKE_LOW 0x8
#define PM_WAKE_BOTH_EDGES (PM_WAKE_RISING | PM_WAKE_FALLING)
#define PM_WAKE_IGNORE 0xF0
int gpio_pm_wakeup_request(unsigned gpio, unsigned char type);
void gpio_pm_wakeup_free(unsigned gpio);
unsigned int gpio_pm_setup(void);
void gpio_pm_restore(void);
struct gpio_port_s {
unsigned short data;
@ -409,6 +412,7 @@ struct gpio_port_s {
unsigned short fer;
unsigned short reserved;
};
#endif /*CONFIG_BF54x*/
#endif /*CONFIG_PM*/
/***********************************************************