Skip to content

Commit

Permalink
Blackfin arch: Functional power management support
Browse files Browse the repository at this point in the history
Enable: PM_SUSPEND_MEM -> Blackfin Hibernate to SDRAM
This feature requires a special bootloader (u-boot)
supporting return from hibernate.

Signed-off-by: Michael Hennerich <[email protected]>
Signed-off-by: Bryan Wu <[email protected]>
  • Loading branch information
mhennerich authored and Bryan Wu committed Jul 19, 2008
1 parent 4f13f54 commit 1efc80b
Show file tree
Hide file tree
Showing 9 changed files with 1,033 additions and 119 deletions.
66 changes: 61 additions & 5 deletions arch/blackfin/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -880,7 +880,7 @@ config ARCH_SUSPEND_POSSIBLE
depends on !SMP

choice
prompt "Default Power Saving Mode"
prompt "Standby Power Saving Mode"
depends on PM
default PM_BFIN_SLEEP_DEEPER
config PM_BFIN_SLEEP_DEEPER
Expand All @@ -899,22 +899,26 @@ config PM_BFIN_SLEEP_DEEPER
normal during Sleep Deeper, due to the reduced SCLK frequency.
When in the sleep mode, system DMA access to L1 memory is not supported.

If unsure, select "Sleep Deeper".

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.
up the processor. When in the sleep mode, system DMA access to L1
memory is not supported.

If unsure, select "Sleep Deeper".
endchoice

config PM_WAKEUP_BY_GPIO
bool "Cause Wakeup Event by GPIO"
bool "Allow Wakeup from Standby by GPIO"

config PM_WAKEUP_GPIO_NUMBER
int "Wakeup GPIO number"
int "GPIO number"
range 0 47
depends on PM_WAKEUP_BY_GPIO
default 2 if BFIN537_STAMP
Expand All @@ -935,6 +939,58 @@ config PM_WAKEUP_GPIO_POLAR_EDGE_B
bool "Both EDGE"
endchoice

comment "Possible Suspend Mem / Hibernate Wake-Up Sources"
depends on PM

config PM_BFIN_WAKE_RTC
bool "Allow Wake-Up from RESET and on-chip RTC"
depends on PM
default n
help
Enable RTC Wake-Up (Voltage Regulator Power-Up)

config PM_BFIN_WAKE_PH6
bool "Allow Wake-Up from on-chip PHY or PH6 GP"
depends on PM && (BF52x || BF534 || BF536 || BF537)
default n
help
Enable PHY and PH6 GP Wake-Up (Voltage Regulator Power-Up)

config PM_BFIN_WAKE_CAN
bool "Allow Wake-Up from on-chip CAN0/1"
depends on PM && (BF54x || BF534 || BF536 || BF537)
default n
help
Enable CAN0/1 Wake-Up (Voltage Regulator Power-Up)

config PM_BFIN_WAKE_GP
bool "Allow Wake-Up from GPIOs"
depends on PM && BF54x
default n
help
Enable General-Purpose Wake-Up (Voltage Regulator Power-Up)

config PM_BFIN_WAKE_USB
bool "Allow Wake-Up from on-chip USB"
depends on PM && (BF54x || BF52x)
default n
help
Enable USB Wake-Up (Voltage Regulator Power-Up)

config PM_BFIN_WAKE_KEYPAD
bool "Allow Wake-Up from on-chip Keypad"
depends on PM && BF54x
default n
help
Enable Keypad Wake-Up (Voltage Regulator Power-Up)

config PM_BFIN_WAKE_ROTARY
bool "Allow Wake-Up from on-chip Rotary"
depends on PM && BF54x
default n
help
Enable Rotary Wake-Up (Voltage Regulator Power-Up)

endmenu

menu "CPU Frequency scaling"
Expand Down
26 changes: 26 additions & 0 deletions arch/blackfin/kernel/bfin_dma_5xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,32 @@ unsigned long get_dma_curr_addr(unsigned int channel)
}
EXPORT_SYMBOL(get_dma_curr_addr);

#ifdef CONFIG_PM
int blackfin_dma_suspend(void)
{
int i;

for (i = 0; i < MAX_BLACKFIN_DMA_CHANNEL; i++) {
if (dma_ch[i].chan_status == DMA_CHANNEL_ENABLED) {
printk(KERN_ERR "DMA Channel %d failed to suspend\n", i);
return -EBUSY;
}

dma_ch[i].saved_peripheral_map = dma_ch[i].regs->peripheral_map;
}

return 0;
}

void blackfin_dma_resume(void)
{
int i;

for (i = 0; i < MAX_BLACKFIN_DMA_CHANNEL; i++)
dma_ch[i].regs->peripheral_map = dma_ch[i].saved_peripheral_map;
}
#endif

static void *__dma_memcpy(void *dest, const void *src, size_t size)
{
int direction; /* 1 - address decrease, 0 - address increase */
Expand Down
118 changes: 112 additions & 6 deletions arch/blackfin/kernel/bfin_gpio.c
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,10 @@ static struct str_ident {
char name[RESOURCE_LABEL_SIZE];
} str_ident[MAX_RESOURCES];

#if defined(CONFIG_PM) && !defined(CONFIG_BF54x)
#if defined(CONFIG_PM)
#if defined(CONFIG_BF54x)
static struct gpio_port_s gpio_bank_saved[gpio_bank(MAX_BLACKFIN_GPIOS)];
#else
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)];
Expand All @@ -206,7 +209,7 @@ static unsigned int sic_iwr_irqs[gpio_bank(MAX_BLACKFIN_GPIOS)] = {IRQ_PORTF_INT
#ifdef BF561_FAMILY
static unsigned int sic_iwr_irqs[gpio_bank(MAX_BLACKFIN_GPIOS)] = {IRQ_PROG0_INTB, IRQ_PROG1_INTB, IRQ_PROG2_INTB};
#endif

#endif
#endif /* CONFIG_PM */

#if defined(BF548_FAMILY)
Expand Down Expand Up @@ -667,7 +670,7 @@ static int bfin_gpio_wakeup_type(unsigned gpio, unsigned char type)
return 0;
}

u32 bfin_pm_setup(void)
u32 bfin_pm_standby_setup(void)
{
u16 bank, mask, i, gpio;

Expand All @@ -679,7 +682,7 @@ u32 bfin_pm_setup(void)
gpio_bankb[bank]->maskb = 0;

if (mask) {
#ifdef BF537_FAMILY
#if defined(BF527_FAMILY) || defined(BF537_FAMILY)
gpio_bank_saved[bank].fer = *port_fer[bank];
#endif
gpio_bank_saved[bank].inen = gpio_bankb[bank]->inen;
Expand Down Expand Up @@ -715,7 +718,7 @@ u32 bfin_pm_setup(void)
return 0;
}

void bfin_pm_restore(void)
void bfin_pm_standby_restore(void)
{
u16 bank, mask, i;

Expand All @@ -724,7 +727,7 @@ void bfin_pm_restore(void)
bank = gpio_bank(i);

if (mask) {
#ifdef BF537_FAMILY
#if defined(BF527_FAMILY) || defined(BF537_FAMILY)
*port_fer[bank] = gpio_bank_saved[bank].fer;
#endif
gpio_bankb[bank]->inen = gpio_bank_saved[bank].inen;
Expand All @@ -743,8 +746,111 @@ void bfin_pm_restore(void)
AWA_DUMMY_READ(maskb);
}

void bfin_gpio_pm_hibernate_suspend(void)
{
int i, bank;

for (i = 0; i < MAX_BLACKFIN_GPIOS; i += GPIO_BANKSIZE) {
bank = gpio_bank(i);

#if defined(BF527_FAMILY) || defined(BF537_FAMILY)
gpio_bank_saved[bank].fer = *port_fer[bank];
#ifdef BF527_FAMILY
gpio_bank_saved[bank].mux = *port_mux[bank];
#else
if (bank == 0)
gpio_bank_saved[bank].mux = bfin_read_PORT_MUX();
#endif
#endif
gpio_bank_saved[bank].data = gpio_bankb[bank]->data;
gpio_bank_saved[bank].inen = gpio_bankb[bank]->inen;
gpio_bank_saved[bank].polar = gpio_bankb[bank]->polar;
gpio_bank_saved[bank].dir = gpio_bankb[bank]->dir;
gpio_bank_saved[bank].edge = gpio_bankb[bank]->edge;
gpio_bank_saved[bank].both = gpio_bankb[bank]->both;
gpio_bank_saved[bank].maska = gpio_bankb[bank]->maska;
}

AWA_DUMMY_READ(maska);
}

void bfin_gpio_pm_hibernate_restore(void)
{
int i, bank;

for (i = 0; i < MAX_BLACKFIN_GPIOS; i += GPIO_BANKSIZE) {
bank = gpio_bank(i);

#if defined(BF527_FAMILY) || defined(BF537_FAMILY)
#ifdef BF527_FAMILY
*port_mux[bank] = gpio_bank_saved[bank].mux;
#else
if (bank == 0)
bfin_write_PORT_MUX(gpio_bank_saved[bank].mux);
#endif
*port_fer[bank] = gpio_bank_saved[bank].fer;
#endif
gpio_bankb[bank]->inen = gpio_bank_saved[bank].inen;
gpio_bankb[bank]->dir = gpio_bank_saved[bank].dir;
gpio_bankb[bank]->polar = gpio_bank_saved[bank].polar;
gpio_bankb[bank]->edge = gpio_bank_saved[bank].edge;
gpio_bankb[bank]->both = gpio_bank_saved[bank].both;

gpio_bankb[bank]->data_set = gpio_bank_saved[bank].data
| gpio_bank_saved[bank].dir;

gpio_bankb[bank]->maska = gpio_bank_saved[bank].maska;
}
AWA_DUMMY_READ(maska);
}


#endif
#else /* BF548_FAMILY */
#ifdef CONFIG_PM

u32 bfin_pm_standby_setup(void)
{
return 0;
}

void bfin_pm_standby_restore(void)
{

}

void bfin_gpio_pm_hibernate_suspend(void)
{
int i, bank;

for (i = 0; i < MAX_BLACKFIN_GPIOS; i += GPIO_BANKSIZE) {
bank = gpio_bank(i);

gpio_bank_saved[bank].fer = gpio_array[bank]->port_fer;
gpio_bank_saved[bank].mux = gpio_array[bank]->port_mux;
gpio_bank_saved[bank].data = gpio_array[bank]->port_data;
gpio_bank_saved[bank].data = gpio_array[bank]->port_data;
gpio_bank_saved[bank].inen = gpio_array[bank]->port_inen;
gpio_bank_saved[bank].dir = gpio_array[bank]->port_dir_set;
}
}

void bfin_gpio_pm_hibernate_restore(void)
{
int i, bank;

for (i = 0; i < MAX_BLACKFIN_GPIOS; i += GPIO_BANKSIZE) {
bank = gpio_bank(i);

gpio_array[bank]->port_mux = gpio_bank_saved[bank].mux;
gpio_array[bank]->port_fer = gpio_bank_saved[bank].fer;
gpio_array[bank]->port_inen = gpio_bank_saved[bank].inen;
gpio_array[bank]->port_dir_set = gpio_bank_saved[bank].dir;
gpio_array[bank]->port_set = gpio_bank_saved[bank].data
| gpio_bank_saved[bank].dir;
}
}
#endif

unsigned short get_gpio_dir(unsigned gpio)
{
Expand Down
Loading

0 comments on commit 1efc80b

Please sign in to comment.