Set power limits on AC plug event

This commit is contained in:
Jeremy Soller
2020-06-17 10:33:56 -06:00
committed by Jeremy Soller
parent 5a8653ef08
commit 90bdcb3818
15 changed files with 191 additions and 22 deletions

View File

@ -2,13 +2,10 @@
set -e set -e
./ectool.sh info has_ec=0
sudo modprobe msr if ./ectool.sh info 2> /dev/null
header=1
if [ -e power.csv ]
then then
header=0 has_ec=1
fi fi
has_dgpu=0 has_dgpu=0
@ -17,6 +14,14 @@ then
has_dgpu=1 has_dgpu=1
fi fi
sudo modprobe msr
header=1
if [ -e power.csv ]
then
header=0
fi
while true while true
do do
if [ "${header}" == "1" ] if [ "${header}" == "1" ]
@ -29,12 +34,18 @@ do
F="${F}\tCPU C" F="${F}\tCPU C"
F="${F}\tCPU TCC" F="${F}\tCPU TCC"
F="${F}\tCPU TJM" F="${F}\tCPU TJM"
F="${F}\tCPU FAN" if [ "${has_ec}" == "1" ]
then
F="${F}\tCPU FAN"
fi
if [ "${has_dgpu}" == "1" ] if [ "${has_dgpu}" == "1" ]
then then
F="${F}\tGPU W" F="${F}\tGPU W"
F="${F}\tGPU C" F="${F}\tGPU C"
F="${F}\tGPU FAN" if [ "${has_ec}" == "1" ]
then
F="${F}\tGPU FAN"
fi
fi fi
else else
F="$(date "+%T")" F="$(date "+%T")"
@ -71,9 +82,12 @@ do
F="${F}\t$(printf "%d" "${TCC}")" F="${F}\t$(printf "%d" "${TCC}")"
F="${F}\t$(printf "%d" "${TJMAX}")" F="${F}\t$(printf "%d" "${TJMAX}")"
D="$(sudo tool/target/release/system76_ectool fan 0)" if [ "${has_ec}" == "1" ]
P="$(echo "(${D} * 100)/255" | bc -lq)" then
F="${F}\t$(printf "%.0f" "${P}")" 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" ] if [ "${has_dgpu}" == "1" ]
then then
@ -83,9 +97,12 @@ do
DGPU_T="$(nvidia-smi --query-gpu=temperature.gpu --format=csv,noheader)" DGPU_T="$(nvidia-smi --query-gpu=temperature.gpu --format=csv,noheader)"
F="${F}\t${DGPU_T}" F="${F}\t${DGPU_T}"
D="$(sudo tool/target/release/system76_ectool fan 1)" if [ "${has_ec}" == "1" ]
P="$(echo "(${D} * 100)/255" | bc -lq)" then
F="${F}\t$(printf "%.0f" "${P}")" 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
fi fi

View File

@ -4,6 +4,7 @@
#include <board/dgpu.h> #include <board/dgpu.h>
#include <board/gpio.h> #include <board/gpio.h>
#include <board/kbc.h> #include <board/kbc.h>
#include <board/peci.h>
#include <board/power.h> #include <board/power.h>
#include <common/debug.h> #include <common/debug.h>
@ -25,10 +26,36 @@ void board_init(void) {
dgpu_init(); 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) { void board_event(void) {
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 (main_cycle == 0) {
bool acin = !gpio_get(&ACIN_N);
gpio_set(&AC_PRESENT, acin);
if (acin) { if (acin) {
// Discharging (no AC adapter) // Discharging (no AC adapter)
gpio_set(&LED_BAT_CHG, false); gpio_set(&LED_BAT_CHG, false);

View File

@ -31,6 +31,11 @@ CFLAGS+=\
-DCHARGER_CHARGE_VOLTAGE=12600 \ -DCHARGER_CHARGE_VOLTAGE=12600 \
-DCHARGER_INPUT_CURRENT=11800 -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 # Enable debug logging over keyboard parallel port
#CFLAGS+=-DPARPORT_DEBUG #CFLAGS+=-DPARPORT_DEBUG

View File

@ -116,7 +116,7 @@ void dgpu_init(void) {
} }
void dgpu_event(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 // Use I2CS if in S0 state
int8_t rlts; int8_t rlts;
int res = i2c_get(&I2C_DGPU, 0x4F, 0x00, &rlts, 1); int res = i2c_get(&I2C_DGPU, 0x4F, 0x00, &rlts, 1);

View File

@ -11,6 +11,7 @@ struct Gpio __code DD_ON = GPIO(E, 4);
struct Gpio __code DGPU_PWR_EN = GPIO(H, 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_EN = GPIO(B, 6); // renamed to SUSBC_EN
struct Gpio __code EC_RSMRST_N = GPIO(E, 5); 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_ACIN = GPIO(C, 7);
struct Gpio __code LED_AIRPLANE_N = GPIO(H, 7); struct Gpio __code LED_AIRPLANE_N = GPIO(H, 7);
struct Gpio __code LED_CAP_N = GPIO(J, 2); struct Gpio __code LED_CAP_N = GPIO(J, 2);

View File

@ -22,6 +22,7 @@ extern struct Gpio __code DD_ON;
extern struct Gpio __code DGPU_PWR_EN; extern struct Gpio __code DGPU_PWR_EN;
extern struct Gpio __code EC_EN; // renamed to SUSBC_EN extern struct Gpio __code EC_EN; // renamed to SUSBC_EN
extern struct Gpio __code EC_RSMRST_N; 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_ACIN;
extern struct Gpio __code LED_AIRPLANE_N; extern struct Gpio __code LED_AIRPLANE_N;
extern struct Gpio __code LED_CAP_N; extern struct Gpio __code LED_CAP_N;

View File

@ -10,6 +10,7 @@ extern uint8_t peci_tcontrol;
extern uint8_t peci_tjmax; extern uint8_t peci_tjmax;
void peci_init(void); void peci_init(void);
int peci_wr_pkg_config(uint8_t index, uint16_t param, uint32_t data);
void peci_event(void); void peci_event(void);
#endif // _BOARD_PECI_H #endif // _BOARD_PECI_H

View File

@ -123,6 +123,57 @@ void peci_init(void) {
PADCTLR = 0x02; 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 // 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) { void peci_event(void) {
if (power_state == POWER_STATE_S0) { if (power_state == POWER_STATE_S0) {

View File

@ -4,6 +4,7 @@
#include <board/dgpu.h> #include <board/dgpu.h>
#include <board/gpio.h> #include <board/gpio.h>
#include <board/kbc.h> #include <board/kbc.h>
#include <board/peci.h>
#include <board/power.h> #include <board/power.h>
#include <common/debug.h> #include <common/debug.h>
@ -26,10 +27,36 @@ void board_init(void) {
dgpu_init(); 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) { void board_event(void) {
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 (main_cycle == 0) {
bool acin = !gpio_get(&ACIN_N);
gpio_set(&AC_PRESENT, acin);
if (acin) { if (acin) {
// Discharging (no AC adapter) // Discharging (no AC adapter)
gpio_set(&LED_BAT_CHG, false); gpio_set(&LED_BAT_CHG, false);

View File

@ -31,6 +31,11 @@ CFLAGS+=\
-DCHARGER_CHARGE_VOLTAGE=16800 \ -DCHARGER_CHARGE_VOLTAGE=16800 \
-DCHARGER_INPUT_CURRENT=9230 -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 # Enable debug logging over keyboard parallel port
#CFLAGS+=-DPARPORT_DEBUG #CFLAGS+=-DPARPORT_DEBUG

View File

@ -116,7 +116,7 @@ void dgpu_init(void) {
} }
void dgpu_event(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 // Use I2CS if in S0 state
int8_t rlts; int8_t rlts;
int res = i2c_get(&I2C_DGPU, 0x4F, 0x00, &rlts, 1); int res = i2c_get(&I2C_DGPU, 0x4F, 0x00, &rlts, 1);

View File

@ -11,6 +11,7 @@ struct Gpio __code CCD_EN = GPIO(D, 1);
struct Gpio __code DD_ON = GPIO(E, 4); struct Gpio __code DD_ON = GPIO(E, 4);
struct Gpio __code DGPU_PWR_EN = GPIO(J, 2); struct Gpio __code DGPU_PWR_EN = GPIO(J, 2);
struct Gpio __code EC_RSMRST_N = GPIO(E, 5); 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_ACIN = GPIO(C, 7);
struct Gpio __code LED_AIRPLANE_N = GPIO(H, 7); struct Gpio __code LED_AIRPLANE_N = GPIO(H, 7);
struct Gpio __code LED_BAT_CHG = GPIO(H, 5); struct Gpio __code LED_BAT_CHG = GPIO(H, 5);

View File

@ -23,6 +23,7 @@ extern struct Gpio __code DD_ON;
extern struct Gpio __code DGPU_PWR_EN; extern struct Gpio __code DGPU_PWR_EN;
#define HAVE_EC_EN 0 #define HAVE_EC_EN 0
extern struct Gpio __code EC_RSMRST_N; 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_ACIN;
extern struct Gpio __code LED_AIRPLANE_N; extern struct Gpio __code LED_AIRPLANE_N;
extern struct Gpio __code LED_BAT_CHG; extern struct Gpio __code LED_BAT_CHG;

View File

@ -4,6 +4,7 @@
#include <board/dgpu.h> #include <board/dgpu.h>
#include <board/gpio.h> #include <board/gpio.h>
#include <board/kbc.h> #include <board/kbc.h>
#include <board/peci.h>
#include <board/power.h> #include <board/power.h>
#include <common/debug.h> #include <common/debug.h>
@ -28,10 +29,36 @@ void board_init(void) {
dgpu_init(); 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) { void board_event(void) {
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 (main_cycle == 0) {
bool acin = !gpio_get(&ACIN_N);
gpio_set(&AC_PRESENT, acin);
if (acin) { if (acin) {
// Discharging (no AC adapter) // Discharging (no AC adapter)
gpio_set(&LED_BAT_CHG, false); gpio_set(&LED_BAT_CHG, false);

View File

@ -31,6 +31,11 @@ CFLAGS+=\
-DCHARGER_CHARGE_VOLTAGE=16800 \ -DCHARGER_CHARGE_VOLTAGE=16800 \
-DCHARGER_INPUT_CURRENT=13050 -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 # Enable debug logging over keyboard parallel port
#CFLAGS+=-DPARPORT_DEBUG #CFLAGS+=-DPARPORT_DEBUG