From: eLinux.org

OMAP Power Management

Contents

PM branch

The PM branch is a developement branch of the linux-omap kernel for the
purposes of developing and stabilizing the PM infrastructure for OMAP
and submitting it upstream.

The maintainer of the PM branch is Kevin Hilman.

Features

  • full-chip retention in idle and suspend
  • full-chip OFF in idle and suspend
  • idle PM via CPUidle
  • support for multiple OMAP3/4 boards

The latest, tested PM branch is available as a branch named
‘pm’
from the linux-omap-pm
repository
.
This branch is also sync’d daily as the ‘pm’ branch of the main
linux-omap
repository
.

Current version

Supported platforms (OMAP3 only)

Tested on the following platforms using omap3_pm_defconfig with
busybox-based initramfs, and tested full-chip RET and OFF in idle and
suspend:

Using OMAP PM

Features

By default, the OMAP is configured to hit full-chip retention in
suspend.

Suspend/Resume
  1. # echo mem > /sys/power/state

Serial console activity or other configured wakeup sources (keypad,
touchscreen) will trigger resume.

Upon resume, you can use the powerdomain state statistics to check
whether all states hit the desired state, cf. ‘Debug info’

  1. # cat /debug/pm_debug/count

In addition, if any power domains did not hit the desired state, you
will see a message on the console.

Enabling system for hitting retention during idle

By default, the UARTs will not automatically idle when unused so they
will prevent low-power states during idle. To enable UART idle timeouts
with a 5 second timeout:

  1. # echo 5 > /sys/devices/platform/omap/omap_uart.0/sleep_timeout
  2. # echo 5 > /sys/devices/platform/omap/omap_uart.1/sleep_timeout
  3. # echo 5 > /sys/devices/platform/omap/omap_uart.2/sleep_timeout
  4. # echo 5 > /sys/devices/platform/omap/omap_uart.3/sleep_timeout

NOTE: the 4th UART is only present on 3630 and OMAP4.

Then, wait for any inactivity timers to expire (such as the 5 second
UART timer) and check the powerdomain transition statistics to see that
transitions are happening

  1. # cat /debug/pm_debug/count
Enabling system for hitting OFF

By default, retention is the deepest sleep state attempted. To enable
power domain transitions to off mode

  1. # echo 1 > /debug/pm_debug/enable_off_mode

Once again, after a suspend or after some idle time, use the power
domain transition stats to check that transitions to off-mode are
happening

  1. # cat /debug/pm_debug/count

Known Problems

  • Zoom2/3: serial console wakeups not working
    • Problem: on suspend, by default the serial driver will disable
      serial interrupts, thus disabling the GPIO IRQ needed for
      wakeup.
    • Fix: enable the wakeup feature for the tty used as console:
  1. # echo enabled > /sys/devices/platform/serial8250.0/tty/ttyS0/power/wakeup
  • GPIO module-level wakeups not always working

    • Background: GPIO wakeups can happen either via the GPIO module
      itself (module-level wakeups) or via IO pad wakeups if the CORE
      powerdomain is inactive, in retention or off.
    • If the IO pad wakeups are not enabled (either because CORE
      remains on, or because IO pad is not armed) GPIO wakeups may not
      happen unless the GPIO module-level wakeups are programmed
      correctly.
    • To ensure GPIO module wakeups are programmed correctly:
      • Enable GPIO IRQ for wakeup GPIO, including ISR. Use
        request_irq()
      • Ensure GPIO is edge-triggered. Only edge triggered GPIOs are
        wakeup capable (c.f. omap34xx TRM Sec. 25.5.3.1)
        • the flags argument of request_irq() should have
          either IRQF_TRIGGER_FALLING, IRQF_TRIGGER_RISING or
          both.
      • Enable GPIO IRQ as wakeup source using
        enable_irq_wake(gpio_to_irq(<gpio>))
    • NOTE: It is very important that an interrupt handler be
      configured for the GPIO IRQ, even if it does nothing but return
      IRQ_HANDLED. This is because without an interrupt handler, the
      GPIO IRQ event will never be properly cleared and this can
      prevent the GPIO module from hitting retention or off on the
      next idle request (c.f. omap34xx TRM Sec. 25.5.3.1).
  • GPIO wakeup works once, but prevents future retention

    • See NOTE just above

Advanced features for PM developers and power users

Debug info

First, mount the debug filesystem (debugfs)

  1. # mount -t debugfs debugfs /debug

Show powerdomain state statistics and clockdomain active clocks

  1. # cat /debug/pm_debug/count

This will look something like this on OMAP3:

  1. # cat /debug/pm_debug/count
  2. cefuse_pwrdm (OFF),OFF:1,RET:0,INA:0,ON:0,RET-LOGIC-OFF:0
  3. always_on_core_pwrdm (OFF),OFF:1,RET:0,INA:0,ON:0,RET-LOGIC-OFF:0
  4. l4per_pwrdm (ON),OFF:0,RET:0,INA:0,ON:1,RET-LOGIC-OFF:0,RET-MEMBANK1-OFF:0,RET-MEMBANK2-OFF:0
  5. l3init_pwrdm (RET),OFF:0,RET:1,INA:0,ON:1,RET-LOGIC-OFF:0,RET-MEMBANK1-OFF:0
  6. cam_pwrdm (OFF),OFF:1,RET:0,INA:0,ON:0,RET-LOGIC-OFF:0,RET-MEMBANK1-OFF:0
  7. ivahd_pwrdm (RET),OFF:1,RET:1,INA:0,ON:1,RET-LOGIC-OFF:0,RET-MEMBANK1-OFF:0,RET-MEMBANK2-OFF:0,RET-MEMBANK3-OFF:0,RET-MEMBANK4-OFF:0
  8. mpu_pwrdm (ON),OFF:0,RET:0,INA:0,ON:1,RET-LOGIC-OFF:0,RET-MEMBANK1-OFF:0,RET-MEMBANK2-OFF:0
  9. cpu1_pwrdm (ON),OFF:0,RET:0,INA:0,ON:1,RET-LOGIC-OFF:0,RET-MEMBANK1-OFF:0
  10. cpu0_pwrdm (ON),OFF:0,RET:0,INA:0,ON:1,RET-LOGIC-OFF:0,RET-MEMBANK1-OFF:0
  11. tesla_pwrdm (RET),OFF:1,RET:1,INA:0,ON:0,RET-LOGIC-OFF:0,RET-MEMBANK1-OFF:0,RET-MEMBANK2-OFF:0,RET-MEMBANK3-OFF:0
  12. dss_pwrdm (RET),OFF:0,RET:1,INA:0,ON:1,RET-LOGIC-OFF:0,RET-MEMBANK1-OFF:0
  13. abe_pwrdm (ON),OFF:1,RET:0,INA:0,ON:1,RET-LOGIC-OFF:0,RET-MEMBANK1-OFF:0,RET-MEMBANK2-OFF:0
  14. gfx_pwrdm (OFF),OFF:2,RET:0,INA:0,ON:1,RET-LOGIC-OFF:0,RET-MEMBANK1-OFF:0
  15. core_pwrdm (ON),OFF:0,RET:0,INA:0,ON:1,RET-LOGIC-OFF:0,RET-MEMBANK1-OFF:0,RET-MEMBANK2-OFF:0,RET-MEMBANK3-OFF:0,RET-MEMBANK4-OFF:0,RET-MEMBANK5-OFF:0

If you see each power domain has counters specified. OFF, RET, INA and
so on…The count basically keeps incrementing every time it hits low
power state. In the above example, cam_pwrdm (camera power domain) has
hit OFF state once. GFX power domain has hit OFF state twice and like
wise.

UART wakeup and timeout options

By default, each of the on-chip OMAP UARTs are enabled as wakeup
sources. In addition, they are configured with a configurable inactivity
timer (default 5 seconds) after which the UART clocks are allowed to be
gated during idle or suspend.

For example, to disable the wakeup capability of a UART1 (a.k.a ttyO0)

  1. # echo disabled > /sys/devices/platform/omap/omap-hsuart.0/power/wakeup

And to change the inactivity timer to 10 seconds, instead of the default
5:

  1. # echo 10 > /sys/devices/platform/omap/omap-hsuart.0/sleep_timeout

Note that you can cat these files under /sys as well to see the
current values.

UART PM Debugging Techniques

Debugging problems with the OMAP UART driver wakeup and data transfer
when Power Management is enabled can be quite tedious, if one does not
have a proper HW setup. An example of a setup (including both HW and SW
changes) can be found in the
OMAP_UART_pm_debugging
page.

Public Power management test framework

Some commonly used power management utilities are listed here which make
sense from an OMAP perspective

Cpufreq utils

cpufreq
utils

for testing dynamic voltage and frequency scaling.

Maemo pm_test

pm-test plugin for Maemo
says

  1. utility which tests that kernel and kernel modules works power management wise

This utility could be used to sanity test the powermanagement impact to
a system for suspend/restore and basic power features.

Quick verification of suspend-idle functionality

the following script may be used with userspace supporting something
simple as busybox:

  1. #!/bin/ash
  2. # Quick script to verify SUSPEND Resume behavior without human intervention
  3. # Refer: http://elinux.org/OMAP_Power_Management for details
  4. # Some params that might change based on the environment
  5. SYS=/sys
  6. DEBUG=$SYS/kernel/debug
  7. PROC=/proc
  8. PMDEBUG=$DEBUG/pm_debug
  9. VOLTAGE_OFF=$PMDEBUG/voltage_off_mode
  10. kver=`uname -r`
  11. if [ $kver > "2.6.36" ]; then
  12. UART="$SYS/devices/platform/omap/omap-hsuart"
  13. else
  14. UART="$SYS/devices/platform/serial8250"
  15. fi
  16. UART1=$UART.0/sleep_timeout
  17. UART2=$UART.1/sleep_timeout
  18. UART3=$UART.2/sleep_timeout
  19. # Setup cpu idle
  20. cpu_idle(){
  21. echo -n "$1" > $PMDEBUG/sleep_while_idle
  22. }
  23. # setup off mode
  24. off_mode(){
  25. echo -n "$1" > $PMDEBUG/enable_off_mode
  26. }
  27. # Do a suspend
  28. suspend_me(){
  29. echo -n "mem" > $SYS/power/state
  30. }
  31. # get my core data (This is the last domain to hit lowest power state)
  32. core_count(){
  33. cat $PMDEBUG/count |grep "^core_pwrdm"
  34. }
  35. # get my retention counter
  36. core_ret_count(){
  37. core_count|cut -d ',' -f3|cut -d ':' -f2
  38. }
  39. # get my off counter
  40. core_off_count(){
  41. core_count|cut -d ',' -f2|cut -d ':' -f2
  42. }
  43. # setup wakeup timer - automated testing
  44. wakeup_timer(){
  45. echo -n "$1" > $PMDEBUG/wakeup_timer_seconds
  46. echo -n "$2" > $PMDEBUG/wakeup_timer_milliseconds
  47. }
  48. # Setup our uart to be inactivity timer
  49. setup_tty_sleep_timeout() {
  50. if [ -f $UART1 ]; then
  51. echo -n "$1" > $UART1
  52. fi
  53. if [ -f $UART2 ]; then
  54. echo -n "$1" > $UART1
  55. fi
  56. if [ -f $UART3 ]; then
  57. echo -n "$1" > $UART3
  58. fi
  59. }
  60. # Measurement Start
  61. measure_start(){
  62. OFF_START=`core_off_count`
  63. RET_START=`core_ret_count`
  64. TIME_START=`date "+%s"`
  65. }
  66. # Measurement End
  67. measure_end(){
  68. OFF_END=`core_off_count`
  69. RET_END=`core_ret_count`
  70. TIME_END=`date "+%s"`
  71. }
  72. # Common formatted print
  73. measure_print(){
  74. DUR=`expr $TIME_END - $TIME_START`
  75. echo "$1 | $2 | OFF: $OFF_START->$OFF_END| RET:$RET_START->$RET_END ($DUR sec)"
  76. }
  77. # verify function
  78. check_core_off(){
  79. RESULT=FAIL
  80. if [ $OFF_START -lt $OFF_END ]; then
  81. RESULT=PASS
  82. fi
  83. }
  84. check_core_ret(){
  85. RESULT=FAIL
  86. if [ $RET_START -lt $RET_END ]; then
  87. RESULT=PASS
  88. fi
  89. }
  90. # Disable everything
  91. disable_all(){
  92. # disable voltage off
  93. if [ -f $VOLTAGE_OFF ]; then
  94. echo -n "0" >$VOLTAGE_OFF
  95. fi
  96. setup_tty_sleep_timeout 0
  97. wakeup_timer 0 0
  98. off_mode 0
  99. cpu_idle 0
  100. }
  101. # test idle - core ret
  102. test_idle_ret() {
  103. disable_all
  104. measure_start
  105. setup_tty_sleep_timeout 5
  106. cpu_idle 1
  107. sleep 20
  108. disable_all
  109. sleep 1;sync
  110. measure_end
  111. check_core_ret
  112. measure_print "IDLE:RET test" $RESULT
  113. }
  114. # test idle - core off
  115. test_idle_off() {
  116. disable_all
  117. measure_start
  118. setup_tty_sleep_timeout 5
  119. off_mode 1
  120. cpu_idle 1
  121. sleep 20
  122. disable_all
  123. sleep 1;sync
  124. measure_end
  125. check_core_off
  126. measure_print "IDLE:OFF test" $RESULT
  127. }
  128. # test suspend - core ret
  129. test_suspend_ret() {
  130. disable_all
  131. measure_start
  132. wakeup_timer 5 0
  133. suspend_me
  134. disable_all
  135. sleep 1;sync
  136. measure_end
  137. check_core_ret
  138. measure_print "SUSPEND:RET test" $RESULT
  139. }
  140. # test suspend - core off
  141. test_suspend_off() {
  142. disable_all
  143. measure_start
  144. off_mode 1
  145. wakeup_timer 5 0
  146. suspend_me
  147. disable_all
  148. sleep 1;sync
  149. measure_end
  150. check_core_off
  151. measure_print "SUSPEND:OFF test" $RESULT
  152. }
  153. # mount up the basic fs
  154. already_mntd=`mount|grep $PROC`
  155. if [ x == x"$already_mntd" ]; then
  156. mount -t proc none $PROC
  157. fi
  158. already_mntd=`mount|grep $SYS`
  159. if [ x == x"$already_mntd" ]; then
  160. mount -t sysfs none $SYS
  161. fi
  162. already_mntd=`mount|grep $DEBUG`
  163. if [ x == x"$already_mntd" ]; then
  164. mount -t debugfs none $DEBUG
  165. fi
  166. # Lets run the tests one by one..
  167. NR=""
  168. R=`test_suspend_off`
  169. echo $R
  170. NR="$NR\n$R"
  171. R=`test_suspend_ret`
  172. echo $R
  173. NR="$NR\n$R"
  174. R=`test_idle_off`
  175. echo $R
  176. NR="$NR\n$R"
  177. R=`test_idle_ret`
  178. echo $R
  179. NR="$NR\n$R"
  180. # Print End result summary
  181. cat $PMDEBUG/count
  182. # Print test summary
  183. echo -e "$NR"

Categories: