Power management is a tricky thing to understand - and even harder thing to implement properly. The words and states that is used to describe the hardware is not the same as the states used to describe the software. The software/hardware interaction is normally defined by the Advanced Configuration and Power Interface (ACPI). ACPI defines common interfaces for hardware recognition, motherboard and device configuration and power management, and is supported by the Linux kernel natively.
The ACPI specification promotes the concept that systems should manage energy consumption by transitioning unused devices into lower power states including placing the entire system in a low-power state (sleeping state) when possible. A system is broken down into classes:
While the Global System is working (on), the processor can be in any number of states, from executing instructions at full rate (G0/C0/P0), to executing instructions at a reduced rate (G0/C0/P4), to waiting for interrupts to occur in a low power mode (G0/C1).
Device states are independent of the system, and are states of particular devices. Device states apply to any device on any bus.
The Blackfin processor provides five operating modes, each with different performance/power/latency profiles. In addition to overall clock management and gating clocks to each of the peripherals, the processor provides the control functions to dynamically alter the processor core supply voltage to further reduce power dissipation. The power states available to the hardware are:
IDLE instruction. The processor remains in the Idle state until a peripheral or external device, generates an interrupt that requires servicing. The kernel IDLE loop is the IDLE state, as it saves power, but has zero overhead in responding to an interrupt.Not all hardware states are available in the Linux kernel.
| Board | Status |
|---|---|
| BF537-EZKit Rev 1.3 Silicon Rev. 0.2 (Ser# 557684) | Failed |
| BF537-EZKit Rev 2.2 Silicon Rev. 0.3 (Ser# 570385) | Failed |
| BF537-EZKit Rev 2.2 Silicon Rev. 0.3 (Ser# 570380) | Failed |
| BF537-STAMP Rev 1.3 Silicon Rev. 0.2 (Ser# 556262) | Failed |
A simple hardware workaround on the SCKE Strobe made the issue go away:
Add a 6.8k Ohm resistor between SCKE (J2-81) and GND (J2-87).
The kernel supports three power management states generically, though each is dependent on platform support code to implement the low-level details for each state. Blackfin Linux currently offers Standby.
“standby”This state offers high power savings, while providing a very low-latency transition back to a working system. No operating state is lost (the CPU retains power), so the system easily starts up again where it left off. From a Blackfin hardware perspective - the processor is in Full On, but the Clocks are slowed down to consume almost no power.
We try to put devices in a low-power state equivalent to D1, which also offers low power savings, but low resume latency. Not all devices support D1, and those that don't are left on.
A transition from Standby to the On state should take only a few milliseconds.
Linux Kernel Configuration ->
Power management options ->
[*] Power Management support
[ ] Legacy Power Management API (DEPRECATED)
[ ] Power Management Debug Support
[*] Suspend to RAM and standby
Standby Power Saving Mode (Sleep Deeper) --->
[*] Allow Wakeup from Standby by GPIO
(2) GPIO number
GPIO Polarity (Active High) --->
--- Possible Suspend Mem / Hibernate Wake-Up Sources
[ ] Allow Wake-Up from on-chip PHY or PH6 GP
There are two different options controlling the Wakeup
Wakeup Events:
For dynamic power management, any of the peripherals can be configured to wake up the core from its idled state to process the interrupt and resume form standby, simply by enabling the appropriate bit in the system interrupt wakeup-enable register (refer to Hardware Reference Manual SIC_IWR).
If a peripheral interrupt source is enabled in SIC_IWR and the core is idled, the interrupt causes the DPMC to initiate the core wakeup sequence in order to process the interrupt.
The linux kernel API provides these three functions to enable or disable wakeup capabilities of interrupts:
int set_irq_wake(irq, state);
int disable_irq_wake(unsigned int irq)
file: trunk/include/linux/interrupt.h
static inline int disable_irq_wake(unsigned int irq) { return set_irq_wake(irq, 0); }
int enable_irq_wake(unsigned int irq)
file: trunk/include/linux/interrupt.h
static inline int enable_irq_wake(unsigned int irq) { return set_irq_wake(irq, 1); }
Example:
Following patch enables irq wake for all gpio-keys push buttons.
Index: drivers/input/keyboard/gpio_keys.c
===================================================================
--- drivers/input/keyboard/gpio_keys.c (revision 4154)
+++ drivers/input/keyboard/gpio_keys.c (working copy)
@@ -100,7 +100,7 @@
irq, error);
goto fail;
}
-
+ enable_irq_wake(irq);
input_set_capability(input, type, button->code);
}
In current kernel versions this feature has been added to the gpio-keys driver
This feature can be enabled by:
root:/sys/devices/platform/gpio-keys.0/power> echo enabled > wakeup
This option adds some extra code that allows specifying any Blackfin GPIO to be configured as Wakeup Strobe.
There is an alternative Blackfin specific API for GPIO wakeups:
This API allows GPIO wakeups without using the Linux interrupt API. It also allows configuring a Wakeup as EDGE or Both EDGE sensitive while the Linux kernel interrupt is configured level sensitive.
#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);
The power management subsystem provides a unified sysfs interface to userspace, regardless of what architecture or platform one is running. The interface exists in /sys/power/ directory (assuming sysfs is mounted at /sys).
/sys/power/state controls system power state. Reading from this file returns what states are supported, which is hard-coded to 'standby' (Power-On Suspend), 'mem' (Suspend-to-RAM), and 'disk' (Suspend-to-Disk).
Blackfin Linux supports:
| Mode | Description |
|---|---|
| standby | Blackfin sleep or sleep_deeper |
| mem | Blackfin Hibernate Suspend-to-Mem |
| disk | NOT AVAILABLE |
Writing to this file one of those strings causes the system to transition into that state. Please see the file Documentation/power/states.txt for a description of each of those states.
root:~> echo standby > /sys/power/state Syncing filesystems ... done. Freezing user space processes ... (elapsed 0.00 seconds) done. Freezing remaining freezable tasks ... (elapsed 0.00 seconds) done. Suspending console(s) * Wakeup Event * Restarting tasks ... done. root:~>
RTC Wakeup in 10 Seconds
root:/> rtcwake -s 10 -m standby wakeup from "standby" at Thu Jan 1 01:45:31 1970 Syncing filesystems ... done. Freezing user space processes ... (elapsed 0.00 seconds) done. Freezing remaining freezable tasks ... (elapsed 0.00 seconds) done. Suspending console(s) Restarting tasks ... done. root:/>
root:~> echo mem > /sys/power/state Syncing filesystems ... done. Freezing user space processes ... (elapsed 0.00 seconds) done. Freezing remaining freezable tasks ... (elapsed 0.00 seconds) done. Suspending console(s) * Wakeup Event * Restarting tasks ... done. root:~>
RTC Wakeup in 10 Seconds
root:/> rtcwake -s 10 -m mem wakeup from "mem" at Thu Jan 1 01:45:31 1970 Syncing filesystems ... done. Freezing user space processes ... (elapsed 0.00 seconds) done. Freezing remaining freezable tasks ... (elapsed 0.00 seconds) done. Suspending console(s) Restarting tasks ... done. root:/>
#include <stdio.h> #include <getopt.h> #include <fcntl.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> static void suspend_system(const char *suspend) { char buf[20]; int f = open("/sys/power/state", O_WRONLY); int len; ssize_t n; if (f < 0) { perror("open /sys/power/state"); return; } len = sprintf(buf, "%s\n", suspend) - 1; len = strlen(buf); n = write(f, buf, len); /* this executes after wake from suspend */ if (n < 0) perror("write /sys/power/state"); else if (n != len) fprintf(stderr, "short write to %s\n", "/sys/power/state"); close(f); } int main(int argc, char **argv) { static char *suspend = "standby"; printf("Going into %s ...\n",suspend); suspend_system(suspend); printf("Awakeing from %s ...\n",suspend); return 0; }
Many operating conditions can affect power dissipation/consumption. System designers should refer to Estimating Power for ADSP-BF531/BF532/BF533 Blackfin Processors (EE-229) on the Analog Devices website (www.analog.com)
EE229 This document provides detailed information
In general:
Derived Power Consumption (PDDTOT)
* PDDTOT = PDDINT + PDDEXT + PDDRTC
Internal Power Consumption (PDDINT)
External Power Consumption (PDDEXT, PDDRTC)
The Standby/sleep mode reduces dynamic power dissipation by disabling the clock to the processor core (CCLK).
Furthermore, Standby/sleep_deeper 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.
Complete Table of Contents/Topics