#!/sbin/openrc-run # # Start-up script to configure droid4 for power management # # Note that the qmi interface for the modem needs autoidle enabled, # please make sure you configured /etc/udev/rules.d/55-modem.rules: # # ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="22b8", \ # ATTRS{idProduct}=="2a70", TEST=="power/control" ATTR{power/control}="auto" # # The LCD needs to be blanked with xset -display :0 dpms force off and # unblanked with xset -display :0 dpms force on to idle DSS clocks. # # Please disable known problem modules for now by adding them into # /etc/modprobe.d/blacklist.conf: # # blacklist ehci-omap # blacklist hci_uart # blacklist omap_hdq # # To monitor power consumption, check the power consumption by reading # the micro-Watts with cat: # # /sys/class/power_supply/battery/power_avg # # To check no device drivers or busy timers are blocking SoC idle states, # check that the RET count keeps increasing when doing: # # grep ^core_pwrdm /sys/kernel/debug/pm_debug/count # # This script can also log the power usage status if run with droid4 status. # You can add it to root crontab to log power consumption once a minute: # # * * * * * /etc/init.d/droid4-pm status >> /var/log/droid4-pm 2>&1 # # And the recent power consumption history can be monitored with: # # tail /var/log/droid4-pm # * d=2020-02-19|t=16:40:00|i=OFF:0,RET:27562|p=61|b=none # * d=2020-02-19|t=16:41:00|i=OFF:0,RET:27962|p=60|b=none # * d=2020-02-19|t=16:42:00|i=OFF:0,RET:28302|p=58|b=none # ... # name="droid4-pm" UART_IDLE_MS=3000 devmem="" rwmem="" blockers="" depend() { if grep -i -e alpine /etc/os-release > /dev/null 2>&1; then need dev after hwdrivers elif grep -i -e devuan /etc/os-release > /dev/null 2>&1; then need eudev after kmod fi } warn_if_module_loaded() { module="${1}" desc="${2}" if lsmod | grep "${module}" > /dev/null; then ewarn "Module ${module} blocks idle: ${desc}" fi } check_module_blacklist() { einfo "Checking for blacklisted modules blocking idle" warn_if_module_loaded ehci-omap "Blocks idle, blacklist?" warn_if_module_loaded omap_hdq "Seems to poll devices, blacklist?" warn_if_module_loaded hci_uart "Blocks uart4 idle oopses on rmmod, blacklist?" warn_if_module_loaded phy-cpcap-usb "Consumes extra 10mW, used by debug UART, unload?" warn_if_module_loaded atmel_mxt_ts "Should be unloaded when screen is blanked" } set_loglevel() { loglevel="${1}" einfo "Setting kernel loglevel to ${loglevel}" echo "${loglevel}" > /proc/sysrq-trigger } idle_uarts() { einfo "Idling UARTs" # Detach kernel serial console consoles=$(find /sys/bus/platform/devices/4*.serial/ -name console) for console in ${consoles}; do echo N > ${console} done # Enable autosuspend uarts=$(find /sys/bus/platform/devices/4*.serial/power/ -type d) for uart in ${uarts}; do echo ${UART_IDLE_MS} > ${uart}/autosuspend_delay_ms echo enabled > ${uart}/wakeup echo auto > ${uart}/control done # Configure wake-up from suspend uarts=$(find /sys/class/tty/tty[SO]*/power/ -type d) for uart in ${uarts}; do echo enabled > ${uart}/wakeup done } enable_soc_idle_states() { einfo "Enabling deeper SoC idle states" echo 1 > /sys/kernel/debug/pm_debug/enable_off_mode } init_reg_read() { if busybox devmem > /dev/null 2>&1; then devmem="busybox devmem" return fi rwmem=$(which rwmem) } check_clkctrl() { address="${1}" idleval="${2}" desc="${3}" if [ "${devmem}" != "" ]; then val=$("${devmem}" "${address}") elif [ "${rwmem}" != "" ]; then val=$("${rwmem}" "${address}" | cut -d' ' -f3) else return fi if [ "${val}" != "${idleval}" ]; then echo -n "${desc}" fi } update_blockers() { address="${1}" idleval="${2}" desc="${3}" device=$(check_clkctrl "${address}" "${idleval}" "${desc}") if [ "${blockers}" = "" ] && [ "${device}" != "" ]; then blockers="${device}" elif [ "${device}" != "" ]; then blockers="${blockers},${device}" fi } check_status() { idle=$(grep ^core_pwrdm /sys/kernel/debug/pm_debug/count | cut -d',' -f2,3) uw=$(cat /sys/class/power_supply/battery/power_avg) mw=$((${uw} / 1000)) if [ -f /sys/class/power_supply/battery/capacity ]; then cap=$(cat /sys/class/power_supply/battery/capacity 2>/dev/null) if [ "${cap}" = "" ]; then cap="NA" fi else cap=0 fi if [ "${reg_read_cmd}" = "" ]; then init_reg_read fi update_blockers 0x4a009540 0x00030000 uart1 update_blockers 0x4a009548 0x00030000 uart2 update_blockers 0x4a009550 0x00030000 uart3 update_blockers 0x4a009558 0x00030000 uart4 update_blockers 0x4a009358 0x00070000 ohci update_blockers 0x4a009360 0x00070000 otg update_blockers 0x4a009368 0x00030000 usbtll update_blockers 0x4a009488 0x00030000 hdq1w update_blockers 0x4a009100 0x00000003 dssst update_blockers 0x4a009120 0x00070000 dss update_blockers 0x4a009220 0x01070000 sgx if [ "${blockers}" = "" ]; then blockers="none" fi date=$(date +%Y-%m-%d) time=$(date +%H:%M:%S) echo "d=${date}|t=${time}|i=${idle}|p=${mw}|c=${cap}|b=${blockers}" } start() { check_module_blacklist idle_uarts set_loglevel 0 enable_soc_idle_states } status() { check_status }