/
n900-pm
executable file
·206 lines (174 loc) · 5.03 KB
/
n900-pm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
#!/sbin/openrc-run
#
# Start-up script to configure n900 for power management
#
# 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/bq27200-0/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 n900 status.
# You can add it to root crontab to log power consumption once a minute:
#
# * * * * * /etc/init.d/n900-pm status >> /var/log/n900-pm 2>&1
#
# And the recent power consumption history can be monitored with:
#
# tail /var/log/n900-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="n900-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 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() {
blocker_bits=$(cat /sys/kernel/debug/pm_debug/count | grep idlest1 | awk '{print $7}')
idle=$(grep ^core_pwrdm /sys/kernel/debug/pm_debug/count | cut -d',' -f2,3)
uw=$(cat /sys/class/power_supply/bq27200-0/power_avg)
mw=$((${uw} / 1000))
cap=$(cat /sys/class/power_supply/bq27200-0/capacity)
if [ "${reg_read_cmd}" = "" ]; then
init_reg_read
fi
blockers=`python3 - $blocker_bits << EOF
import sys
# 31 to 0
cm_idlest1_core_bits = [ 'RESERVED', 'ST_MMC3', 'ST_ICR',
'RESERVED', 'RESERVED', 'RESERVED', 'ST_MMC2', 'ST_MMC1',
'RESERVED', 'ST_HDQ', 'ST_MCSPI4', 'ST_MCSPI3', 'ST_MCSPI2',
'ST_MCSPI1', 'ST_I2C3', 'ST_I2C2', 'ST_I2C1', 'ST_UART2',
'ST_UART1', 'ST_GPT11', 'ST_GPT10', 'ST_MCBSP5', 'ST_MCBSP1',
'RESERVED', 'ST_MAILBOXES', 'ST_OMAPCTRL', 'ST_HSOTGUSB_IDLE',
'ST_HSOTGUSB_STDBY', 'RESERVED', 'ST_SDMA', 'ST_SDRC', 'RESERVED',
]
cm_idlest1_core_bits = list(reversed(cm_idlest1_core_bits))
inp = sys.argv[1]
v = int(inp, 16)
b= '{0:b}'.format(v)
blockers = []
for i in range(0, 32):
is_set = (v & (1 << i)) >> i
if is_set:
blockers.append(cm_idlest1_core_bits[i])
print(','.join(blockers),end='')
EOF`
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
}