Set power limits on AC plug event
This commit is contained in:
committed by
Jeremy Soller
parent
5a8653ef08
commit
90bdcb3818
29
power.sh
29
power.sh
@ -2,13 +2,10 @@
|
||||
|
||||
set -e
|
||||
|
||||
./ectool.sh info
|
||||
sudo modprobe msr
|
||||
|
||||
header=1
|
||||
if [ -e power.csv ]
|
||||
has_ec=0
|
||||
if ./ectool.sh info 2> /dev/null
|
||||
then
|
||||
header=0
|
||||
has_ec=1
|
||||
fi
|
||||
|
||||
has_dgpu=0
|
||||
@ -17,6 +14,14 @@ then
|
||||
has_dgpu=1
|
||||
fi
|
||||
|
||||
sudo modprobe msr
|
||||
|
||||
header=1
|
||||
if [ -e power.csv ]
|
||||
then
|
||||
header=0
|
||||
fi
|
||||
|
||||
while true
|
||||
do
|
||||
if [ "${header}" == "1" ]
|
||||
@ -29,13 +34,19 @@ do
|
||||
F="${F}\tCPU C"
|
||||
F="${F}\tCPU TCC"
|
||||
F="${F}\tCPU TJM"
|
||||
if [ "${has_ec}" == "1" ]
|
||||
then
|
||||
F="${F}\tCPU FAN"
|
||||
fi
|
||||
if [ "${has_dgpu}" == "1" ]
|
||||
then
|
||||
F="${F}\tGPU W"
|
||||
F="${F}\tGPU C"
|
||||
if [ "${has_ec}" == "1" ]
|
||||
then
|
||||
F="${F}\tGPU FAN"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
F="$(date "+%T")"
|
||||
|
||||
@ -71,9 +82,12 @@ do
|
||||
F="${F}\t$(printf "%d" "${TCC}")"
|
||||
F="${F}\t$(printf "%d" "${TJMAX}")"
|
||||
|
||||
if [ "${has_ec}" == "1" ]
|
||||
then
|
||||
D="$(sudo tool/target/release/system76_ectool fan 0)"
|
||||
P="$(echo "(${D} * 100)/255" | bc -lq)"
|
||||
F="${F}\t$(printf "%.0f" "${P}")"
|
||||
fi
|
||||
|
||||
if [ "${has_dgpu}" == "1" ]
|
||||
then
|
||||
@ -83,11 +97,14 @@ do
|
||||
DGPU_T="$(nvidia-smi --query-gpu=temperature.gpu --format=csv,noheader)"
|
||||
F="${F}\t${DGPU_T}"
|
||||
|
||||
if [ "${has_ec}" == "1" ]
|
||||
then
|
||||
D="$(sudo tool/target/release/system76_ectool fan 1)"
|
||||
P="$(echo "(${D} * 100)/255" | bc -lq)"
|
||||
F="${F}\t$(printf "%.0f" "${P}")"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
for file in /sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq
|
||||
do
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <board/dgpu.h>
|
||||
#include <board/gpio.h>
|
||||
#include <board/kbc.h>
|
||||
#include <board/peci.h>
|
||||
#include <board/power.h>
|
||||
#include <common/debug.h>
|
||||
|
||||
@ -25,10 +26,36 @@ void board_init(void) {
|
||||
dgpu_init();
|
||||
}
|
||||
|
||||
// Set PL4 using PECI
|
||||
static int set_power_limit(uint8_t watts) {
|
||||
return peci_wr_pkg_config(
|
||||
60, // index
|
||||
0, // param
|
||||
((uint32_t)watts) * 8
|
||||
);
|
||||
}
|
||||
|
||||
void board_event(void) {
|
||||
if (main_cycle == 0) {
|
||||
bool acin = !gpio_get(&ACIN_N);
|
||||
gpio_set(&AC_PRESENT, acin);
|
||||
|
||||
static uint8_t last_power_limit = 0;
|
||||
if (power_state == POWER_STATE_S0) {
|
||||
uint8_t power_limit = acin ? POWER_LIMIT_AC : POWER_LIMIT_DC;
|
||||
if (power_limit != last_power_limit) {
|
||||
int res = set_power_limit(power_limit);
|
||||
DEBUG("set_power_limit %d = %d\n", power_limit, res);
|
||||
if (res >= 0) {
|
||||
last_power_limit = power_limit;
|
||||
} else {
|
||||
ERROR("set_power_limit failed: %X\n", -res);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
last_power_limit = 0;
|
||||
}
|
||||
|
||||
if (main_cycle == 0) {
|
||||
if (acin) {
|
||||
// Discharging (no AC adapter)
|
||||
gpio_set(&LED_BAT_CHG, false);
|
||||
|
@ -31,6 +31,11 @@ CFLAGS+=\
|
||||
-DCHARGER_CHARGE_VOLTAGE=12600 \
|
||||
-DCHARGER_INPUT_CURRENT=11800
|
||||
|
||||
# Set CPU power limits in watts
|
||||
CFLAGS+=\
|
||||
-DPOWER_LIMIT_AC=180 \
|
||||
-DPOWER_LIMIT_DC=28
|
||||
|
||||
# Enable debug logging over keyboard parallel port
|
||||
#CFLAGS+=-DPARPORT_DEBUG
|
||||
|
||||
|
@ -116,7 +116,7 @@ void dgpu_init(void) {
|
||||
}
|
||||
|
||||
void dgpu_event(void) {
|
||||
if (power_state == POWER_STATE_S0 && gpio_get(&DGPU_PWR_EN)) {
|
||||
if (power_state == POWER_STATE_S0 && gpio_get(&DGPU_PWR_EN) && !gpio_get(&GC6_FB_EN)) {
|
||||
// Use I2CS if in S0 state
|
||||
int8_t rlts;
|
||||
int res = i2c_get(&I2C_DGPU, 0x4F, 0x00, &rlts, 1);
|
||||
|
@ -11,6 +11,7 @@ struct Gpio __code DD_ON = GPIO(E, 4);
|
||||
struct Gpio __code DGPU_PWR_EN = GPIO(H, 4);
|
||||
struct Gpio __code EC_EN = GPIO(B, 6); // renamed to SUSBC_EN
|
||||
struct Gpio __code EC_RSMRST_N = GPIO(E, 5);
|
||||
struct Gpio __code GC6_FB_EN = GPIO(H, 3);
|
||||
struct Gpio __code LED_ACIN = GPIO(C, 7);
|
||||
struct Gpio __code LED_AIRPLANE_N = GPIO(H, 7);
|
||||
struct Gpio __code LED_CAP_N = GPIO(J, 2);
|
||||
|
@ -22,6 +22,7 @@ extern struct Gpio __code DD_ON;
|
||||
extern struct Gpio __code DGPU_PWR_EN;
|
||||
extern struct Gpio __code EC_EN; // renamed to SUSBC_EN
|
||||
extern struct Gpio __code EC_RSMRST_N;
|
||||
extern struct Gpio __code GC6_FB_EN;
|
||||
extern struct Gpio __code LED_ACIN;
|
||||
extern struct Gpio __code LED_AIRPLANE_N;
|
||||
extern struct Gpio __code LED_CAP_N;
|
||||
|
@ -10,6 +10,7 @@ extern uint8_t peci_tcontrol;
|
||||
extern uint8_t peci_tjmax;
|
||||
|
||||
void peci_init(void);
|
||||
int peci_wr_pkg_config(uint8_t index, uint16_t param, uint32_t data);
|
||||
void peci_event(void);
|
||||
|
||||
#endif // _BOARD_PECI_H
|
||||
|
@ -123,6 +123,57 @@ void peci_init(void) {
|
||||
PADCTLR = 0x02;
|
||||
}
|
||||
|
||||
// Returns positive completion code on success, negative completion code or
|
||||
// negative (0x1000 | status register) on PECI hardware error
|
||||
int peci_wr_pkg_config(uint8_t index, uint16_t param, uint32_t data) {
|
||||
// Wait for completion
|
||||
while (HOSTAR & 1) {}
|
||||
// Clear status
|
||||
HOSTAR = HOSTAR;
|
||||
|
||||
// Enable PECI, clearing data fifo's, enable AW_FCS
|
||||
HOCTLR = (1 << 5) | (1 << 3) | (1 << 1);
|
||||
// Set address to default
|
||||
HOTRADDR = 0x30;
|
||||
// Set write length
|
||||
HOWRLR = 10;
|
||||
// Set read length
|
||||
HORDLR = 1;
|
||||
// Set command
|
||||
HOCMDR = 0xA5;
|
||||
|
||||
// Write host ID
|
||||
HOWRDR = 0;
|
||||
// Write index
|
||||
HOWRDR = index;
|
||||
// Write param
|
||||
HOWRDR = (uint8_t)param;
|
||||
HOWRDR = (uint8_t)(param >> 8);
|
||||
// Write data
|
||||
HOWRDR = (uint8_t)data;
|
||||
HOWRDR = (uint8_t)(data >> 8);
|
||||
HOWRDR = (uint8_t)(data >> 16);
|
||||
HOWRDR = (uint8_t)(data >> 24);
|
||||
|
||||
// Start transaction
|
||||
HOCTLR |= 1;
|
||||
|
||||
// Wait for completion
|
||||
while (HOSTAR & 1) {}
|
||||
|
||||
int status = (int)HOSTAR;
|
||||
if (status & (1 << 1)) {
|
||||
int cc = (int)HORDDR;
|
||||
if (cc & 0x80) {
|
||||
return -cc;
|
||||
} else {
|
||||
return cc;
|
||||
}
|
||||
} else {
|
||||
return -(0x1000 | status);
|
||||
}
|
||||
}
|
||||
|
||||
// PECI information can be found here: https://www.intel.com/content/dam/www/public/us/en/documents/design-guides/core-i7-lga-2011-guide.pdf
|
||||
void peci_event(void) {
|
||||
if (power_state == POWER_STATE_S0) {
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <board/dgpu.h>
|
||||
#include <board/gpio.h>
|
||||
#include <board/kbc.h>
|
||||
#include <board/peci.h>
|
||||
#include <board/power.h>
|
||||
#include <common/debug.h>
|
||||
|
||||
@ -26,10 +27,36 @@ void board_init(void) {
|
||||
dgpu_init();
|
||||
}
|
||||
|
||||
// Set PL4 using PECI
|
||||
static int set_power_limit(uint8_t watts) {
|
||||
return peci_wr_pkg_config(
|
||||
60, // index
|
||||
0, // param
|
||||
((uint32_t)watts) * 8
|
||||
);
|
||||
}
|
||||
|
||||
void board_event(void) {
|
||||
if (main_cycle == 0) {
|
||||
bool acin = !gpio_get(&ACIN_N);
|
||||
gpio_set(&AC_PRESENT, acin);
|
||||
|
||||
static uint8_t last_power_limit = 0;
|
||||
if (power_state == POWER_STATE_S0) {
|
||||
uint8_t power_limit = acin ? POWER_LIMIT_AC : POWER_LIMIT_DC;
|
||||
if (power_limit != last_power_limit) {
|
||||
int res = set_power_limit(power_limit);
|
||||
DEBUG("set_power_limit %d = %d\n", power_limit, res);
|
||||
if (res >= 0) {
|
||||
last_power_limit = power_limit;
|
||||
} else {
|
||||
ERROR("set_power_limit failed: %X\n", -res);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
last_power_limit = 0;
|
||||
}
|
||||
|
||||
if (main_cycle == 0) {
|
||||
if (acin) {
|
||||
// Discharging (no AC adapter)
|
||||
gpio_set(&LED_BAT_CHG, false);
|
||||
|
@ -31,6 +31,11 @@ CFLAGS+=\
|
||||
-DCHARGER_CHARGE_VOLTAGE=16800 \
|
||||
-DCHARGER_INPUT_CURRENT=9230
|
||||
|
||||
# Set CPU power limits in watts
|
||||
CFLAGS+=\
|
||||
-DPOWER_LIMIT_AC=180 \
|
||||
-DPOWER_LIMIT_DC=28
|
||||
|
||||
# Enable debug logging over keyboard parallel port
|
||||
#CFLAGS+=-DPARPORT_DEBUG
|
||||
|
||||
|
@ -116,7 +116,7 @@ void dgpu_init(void) {
|
||||
}
|
||||
|
||||
void dgpu_event(void) {
|
||||
if (power_state == POWER_STATE_S0 && gpio_get(&DGPU_PWR_EN)) {
|
||||
if (power_state == POWER_STATE_S0 && gpio_get(&DGPU_PWR_EN) && !gpio_get(&GC6_FB_EN)) {
|
||||
// Use I2CS if in S0 state
|
||||
int8_t rlts;
|
||||
int res = i2c_get(&I2C_DGPU, 0x4F, 0x00, &rlts, 1);
|
||||
|
@ -11,6 +11,7 @@ struct Gpio __code CCD_EN = GPIO(D, 1);
|
||||
struct Gpio __code DD_ON = GPIO(E, 4);
|
||||
struct Gpio __code DGPU_PWR_EN = GPIO(J, 2);
|
||||
struct Gpio __code EC_RSMRST_N = GPIO(E, 5);
|
||||
struct Gpio __code GC6_FB_EN = GPIO(J, 3);
|
||||
struct Gpio __code LED_ACIN = GPIO(C, 7);
|
||||
struct Gpio __code LED_AIRPLANE_N = GPIO(H, 7);
|
||||
struct Gpio __code LED_BAT_CHG = GPIO(H, 5);
|
||||
|
@ -23,6 +23,7 @@ extern struct Gpio __code DD_ON;
|
||||
extern struct Gpio __code DGPU_PWR_EN;
|
||||
#define HAVE_EC_EN 0
|
||||
extern struct Gpio __code EC_RSMRST_N;
|
||||
extern struct Gpio __code GC6_FB_EN;
|
||||
extern struct Gpio __code LED_ACIN;
|
||||
extern struct Gpio __code LED_AIRPLANE_N;
|
||||
extern struct Gpio __code LED_BAT_CHG;
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <board/dgpu.h>
|
||||
#include <board/gpio.h>
|
||||
#include <board/kbc.h>
|
||||
#include <board/peci.h>
|
||||
#include <board/power.h>
|
||||
#include <common/debug.h>
|
||||
|
||||
@ -28,10 +29,36 @@ void board_init(void) {
|
||||
dgpu_init();
|
||||
}
|
||||
|
||||
// Set PL4 using PECI
|
||||
static int set_power_limit(uint8_t watts) {
|
||||
return peci_wr_pkg_config(
|
||||
60, // index
|
||||
0, // param
|
||||
((uint32_t)watts) * 8
|
||||
);
|
||||
}
|
||||
|
||||
void board_event(void) {
|
||||
if (main_cycle == 0) {
|
||||
bool acin = !gpio_get(&ACIN_N);
|
||||
gpio_set(&AC_PRESENT, acin);
|
||||
|
||||
static uint8_t last_power_limit = 0;
|
||||
if (power_state == POWER_STATE_S0) {
|
||||
uint8_t power_limit = acin ? POWER_LIMIT_AC : POWER_LIMIT_DC;
|
||||
if (power_limit != last_power_limit) {
|
||||
int res = set_power_limit(power_limit);
|
||||
DEBUG("set_power_limit %d = %d\n", power_limit, res);
|
||||
if (res >= 0) {
|
||||
last_power_limit = power_limit;
|
||||
} else {
|
||||
ERROR("set_power_limit failed: %X\n", -res);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
last_power_limit = 0;
|
||||
}
|
||||
|
||||
if (main_cycle == 0) {
|
||||
if (acin) {
|
||||
// Discharging (no AC adapter)
|
||||
gpio_set(&LED_BAT_CHG, false);
|
||||
|
@ -31,6 +31,11 @@ CFLAGS+=\
|
||||
-DCHARGER_CHARGE_VOLTAGE=16800 \
|
||||
-DCHARGER_INPUT_CURRENT=13050
|
||||
|
||||
# Set CPU power limits in watts
|
||||
CFLAGS+=\
|
||||
-DPOWER_LIMIT_AC=180 \
|
||||
-DPOWER_LIMIT_DC=28
|
||||
|
||||
# Enable debug logging over keyboard parallel port
|
||||
#CFLAGS+=-DPARPORT_DEBUG
|
||||
|
||||
|
Reference in New Issue
Block a user