[Blackfin] arch: hook up set_irq_wake in Blackfin's irq code
authorMichael Hennerich <michael.hennerich@analog.com>
Fri, 8 Feb 2008 20:12:37 +0000 (04:12 +0800)
committerBryan Wu <bryan.wu@analog.com>
Fri, 8 Feb 2008 20:12:37 +0000 (04:12 +0800)
 - 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>
arch/blackfin/Kconfig
arch/blackfin/kernel/bfin_gpio.c
arch/blackfin/mach-common/dpmc.S
arch/blackfin/mach-common/ints-priority.c
arch/blackfin/mach-common/pm.c
include/asm-blackfin/bfin-global.h
include/asm-blackfin/dpmc.h
include/asm-blackfin/gpio.h

index ba21e33..368bc7f 100644 (file)
@@ -544,7 +544,7 @@ config EXCPT_IRQ_SYSC_L1
        default y
        help
          If enabled, the entire ASM lowlevel exception and interrupt entry code
-         (STORE/RESTORE CONTEXT) is linked into L1 instruction memory. 
+         (STORE/RESTORE CONTEXT) is linked into L1 instruction memory.
          (less latency)
 
 config DO_IRQ_L1
@@ -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
-       help
-         If you have a GPIO already configured as input with the corresponding PORTx_MASK
-         bit set - "Specify Wakeup Event by SIC_IWR value"
+       default PM_BFIN_SLEEP_DEEPER
+config  PM_BFIN_SLEEP_DEEPER
+       bool "Sleep Deeper"
+       help
+         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_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"
-
-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_GPIO_NUMBER
        int "Wakeup GPIO number"
index 6bbe0a2..08788f7 100644 (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;
index b82c096..b80ddd8 100644 (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;
 
index 166dbba..81d0018 100644 (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,
index 81930f7..0be805c 100644 (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,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);
 }
 
 /*
index 6ae0619..5dba3a7 100644 (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;
index f162edb..686cf83 100644 (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);
index d0426c1..27ff532 100644 (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*/
 
 /***********************************************************