commit
9ee71097f9
2
.gitignore
vendored
2
.gitignore
vendored
@ -1 +1,3 @@
|
|||||||
/build/
|
/build/
|
||||||
|
backup.rom
|
||||||
|
power.csv
|
||||||
|
63
power.sh
Executable file
63
power.sh
Executable file
@ -0,0 +1,63 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
./ectool.sh info
|
||||||
|
|
||||||
|
header=1
|
||||||
|
if [ -e power.csv ]
|
||||||
|
then
|
||||||
|
header=0
|
||||||
|
fi
|
||||||
|
|
||||||
|
while true
|
||||||
|
do
|
||||||
|
if [ "${header}" == "1" ]
|
||||||
|
then
|
||||||
|
F="Time "
|
||||||
|
F="${F}\tBAT W"
|
||||||
|
F="${F}\tCPU W"
|
||||||
|
F="${F}\tCPU C"
|
||||||
|
F="${F}\tFAN %"
|
||||||
|
else
|
||||||
|
F="$(date "+%T")"
|
||||||
|
|
||||||
|
uV="$(cat /sys/class/power_supply/BAT0/voltage_now)"
|
||||||
|
V="$(echo "${uV}/1000000" | bc -lq)"
|
||||||
|
uA="$(cat /sys/class/power_supply/BAT0/current_now)"
|
||||||
|
A="$(echo "${uA}/1000000" | bc -lq)"
|
||||||
|
bat_W="$(echo "${V} * ${A}" | bc -lq)"
|
||||||
|
F="${F}\t$(printf "%.2f" "${bat_W}")"
|
||||||
|
|
||||||
|
last_E="$(cat /sys/class/powercap/intel-rapl\:0/energy_uj)"
|
||||||
|
sleep 1
|
||||||
|
next_E="$(cat /sys/class/powercap/intel-rapl\:0/energy_uj)"
|
||||||
|
W="$(echo "(${next_E} - ${last_E})/1000000" | bc -lq)"
|
||||||
|
F="${F}\t$(printf "%.1f" "${W}")"
|
||||||
|
|
||||||
|
T="$(cat /sys/devices/platform/coretemp.0/hwmon/hwmon*/temp1_input)"
|
||||||
|
C="$(echo "${T}/1000" | bc -lq)"
|
||||||
|
F="${F}\t$(printf "%.1f" "${C}")"
|
||||||
|
|
||||||
|
D="$(sudo tool/target/release/system76_ectool fan 0)"
|
||||||
|
P="$(echo "(${D} * 100)/255" | bc -lq)"
|
||||||
|
F="${F}\t$(printf "%.0f" "${P}")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
for file in /sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq
|
||||||
|
do
|
||||||
|
if [ "${header}" == "1" ]
|
||||||
|
then
|
||||||
|
id="$(basename "$(dirname "$(dirname "${file}")")")"
|
||||||
|
F="${F}\t${id}"
|
||||||
|
else
|
||||||
|
KHz="$(cat "${file}")"
|
||||||
|
MHz="$(echo "${KHz}/1000" | bc -lq)"
|
||||||
|
F="${F}\t$(printf "%.0f" "${MHz}")"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo -e "${F}" | tee -a power.csv
|
||||||
|
|
||||||
|
header=0
|
||||||
|
done
|
@ -7,6 +7,12 @@
|
|||||||
#include <ec/gpio.h>
|
#include <ec/gpio.h>
|
||||||
#include <ec/pwm.h>
|
#include <ec/pwm.h>
|
||||||
|
|
||||||
|
// Fan speed is the lowest requested over HEATUP seconds
|
||||||
|
#define HEATUP 5
|
||||||
|
|
||||||
|
// Fan speed is the highest HEATUP speed over COOLDOWN seconds
|
||||||
|
#define COOLDOWN 10
|
||||||
|
|
||||||
// Tjunction = 100C for i7-8565U (and probably the same for all WHL-U)
|
// Tjunction = 100C for i7-8565U (and probably the same for all WHL-U)
|
||||||
#define T_JUNCTION 100
|
#define T_JUNCTION 100
|
||||||
|
|
||||||
@ -30,7 +36,7 @@ struct FanPoint __code FAN_POINTS[] = {
|
|||||||
FAN_POINT(70, 45),
|
FAN_POINT(70, 45),
|
||||||
FAN_POINT(75, 55),
|
FAN_POINT(75, 55),
|
||||||
FAN_POINT(80, 75),
|
FAN_POINT(80, 75),
|
||||||
FAN_POINT(84, 100),
|
FAN_POINT(84, 100)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get duty cycle based on temperature, adapted from
|
// Get duty cycle based on temperature, adapted from
|
||||||
@ -51,12 +57,14 @@ uint8_t fan_duty(int16_t temp) {
|
|||||||
|
|
||||||
// If in between current temp and previous temp, interpolate
|
// If in between current temp and previous temp, interpolate
|
||||||
if (temp > prev->temp) {
|
if (temp > prev->temp) {
|
||||||
int16_t dtemp = (cur->temp - prev->temp);
|
return prev->duty;
|
||||||
int16_t dduty = ((int16_t)cur->duty) - ((int16_t)prev->duty);
|
|
||||||
return (uint8_t)(
|
// int16_t dtemp = (cur->temp - prev->temp);
|
||||||
((int16_t)prev->duty) +
|
// int16_t dduty = ((int16_t)cur->duty) - ((int16_t)prev->duty);
|
||||||
((temp - prev->temp) * dduty) / dtemp
|
// return (uint8_t)(
|
||||||
);
|
// ((int16_t)prev->duty) +
|
||||||
|
// ((temp - prev->temp) * dduty) / dtemp
|
||||||
|
// );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -66,6 +74,40 @@ uint8_t fan_duty(int16_t temp) {
|
|||||||
return PWM_DUTY(100);
|
return PWM_DUTY(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t fan_heatup(uint8_t duty) {
|
||||||
|
static uint8_t history[HEATUP] = { 0 };
|
||||||
|
uint8_t lowest = duty;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for (i = 0; (i + 1) < ARRAY_SIZE(history); i++) {
|
||||||
|
uint8_t value = history[i + 1];
|
||||||
|
if (value < lowest) {
|
||||||
|
lowest = value;
|
||||||
|
}
|
||||||
|
history[i] = value;
|
||||||
|
}
|
||||||
|
history[i] = duty;
|
||||||
|
|
||||||
|
return lowest;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t fan_cooldown(uint8_t duty) {
|
||||||
|
static uint8_t history[COOLDOWN] = { 0 };
|
||||||
|
uint8_t highest = duty;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for (i = 0; (i + 1) < ARRAY_SIZE(history); i++) {
|
||||||
|
uint8_t value = history[i + 1];
|
||||||
|
if (value > highest) {
|
||||||
|
highest = value;
|
||||||
|
}
|
||||||
|
history[i] = value;
|
||||||
|
}
|
||||||
|
history[i] = duty;
|
||||||
|
|
||||||
|
return highest;
|
||||||
|
}
|
||||||
|
|
||||||
void peci_init(void) {
|
void peci_init(void) {
|
||||||
// Allow PECI pin to be used
|
// Allow PECI pin to be used
|
||||||
GCR2 |= (1 << 4);
|
GCR2 |= (1 << 4);
|
||||||
@ -123,8 +165,10 @@ void peci_event(void) {
|
|||||||
peci_duty = PWM_DUTY(0);
|
peci_duty = PWM_DUTY(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (peci_duty != DCR2) {
|
uint8_t heatup_duty = fan_heatup(peci_duty);
|
||||||
DCR2 = peci_duty;
|
uint8_t cooldown_duty = fan_cooldown(heatup_duty);
|
||||||
DEBUG("PECI offset=%d, temp=%d = %d\n", peci_offset, peci_temp, peci_duty);
|
if (cooldown_duty != DCR2) {
|
||||||
|
DCR2 = cooldown_duty;
|
||||||
|
DEBUG("PECI offset=%d, temp=%d = %d\n", peci_offset, peci_temp, cooldown_duty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -386,11 +386,10 @@ void power_event(void) {
|
|||||||
// state is S3
|
// state is S3
|
||||||
static bool ack_last = false;
|
static bool ack_last = false;
|
||||||
bool ack_new = gpio_get(&SUSWARN_N);
|
bool ack_new = gpio_get(&SUSWARN_N);
|
||||||
|
#if LEVEL >= LEVEL_DEBUG
|
||||||
if (ack_new && !ack_last) {
|
if (ack_new && !ack_last) {
|
||||||
DEBUG("%02X: SUSPWRDNACK asserted\n", main_cycle);
|
DEBUG("%02X: SUSPWRDNACK asserted\n", main_cycle);
|
||||||
}
|
} else if (!ack_new && ack_last) {
|
||||||
#if LEVEL >= LEVEL_DEBUG
|
|
||||||
else if (!ack_new && ack_last) {
|
|
||||||
DEBUG("%02X: SUSPWRDNACK de-asserted\n", main_cycle);
|
DEBUG("%02X: SUSPWRDNACK de-asserted\n", main_cycle);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include <common/command.h>
|
#include <common/command.h>
|
||||||
#include <common/macro.h>
|
#include <common/macro.h>
|
||||||
#include <common/version.h>
|
#include <common/version.h>
|
||||||
|
#include <ec/pwm.h>
|
||||||
|
|
||||||
// Shared memory host semaphore
|
// Shared memory host semaphore
|
||||||
volatile uint8_t __xdata __at(0x1022) SMHSR;
|
volatile uint8_t __xdata __at(0x1022) SMHSR;
|
||||||
@ -143,6 +144,30 @@ static enum Result cmd_reset(void) {
|
|||||||
return RES_ERR;
|
return RES_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static enum Result cmd_fan_get(void) {
|
||||||
|
// If setting fan 0
|
||||||
|
if (smfi_cmd[2] == 0) {
|
||||||
|
// Get duty of fan 0
|
||||||
|
smfi_cmd[3] = DCR2;
|
||||||
|
return RES_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Failed if fan not found
|
||||||
|
return RES_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum Result cmd_fan_set(void) {
|
||||||
|
// If setting fan 0
|
||||||
|
if (smfi_cmd[2] == 0) {
|
||||||
|
// Set duty cycle of fan 0
|
||||||
|
DCR2 = smfi_cmd[3];
|
||||||
|
return RES_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Failed if fan not found
|
||||||
|
return RES_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
void smfi_event(void) {
|
void smfi_event(void) {
|
||||||
if (smfi_cmd[0]) {
|
if (smfi_cmd[0]) {
|
||||||
switch (smfi_cmd[0]) {
|
switch (smfi_cmd[0]) {
|
||||||
@ -174,6 +199,14 @@ void smfi_event(void) {
|
|||||||
case CMD_RESET:
|
case CMD_RESET:
|
||||||
smfi_cmd[1] = cmd_reset();
|
smfi_cmd[1] = cmd_reset();
|
||||||
break;
|
break;
|
||||||
|
#ifndef __SCRATCH__
|
||||||
|
case CMD_FAN_GET:
|
||||||
|
smfi_cmd[1] = cmd_fan_get();
|
||||||
|
break;
|
||||||
|
case CMD_FAN_SET:
|
||||||
|
smfi_cmd[1] = cmd_fan_set();
|
||||||
|
break;
|
||||||
|
#endif // __SCRATCH__
|
||||||
default:
|
default:
|
||||||
// Command not found
|
// Command not found
|
||||||
smfi_cmd[1] = RES_ERR;
|
smfi_cmd[1] = RES_ERR;
|
||||||
|
@ -7,6 +7,12 @@
|
|||||||
#include <ec/gpio.h>
|
#include <ec/gpio.h>
|
||||||
#include <ec/pwm.h>
|
#include <ec/pwm.h>
|
||||||
|
|
||||||
|
// Fan speed is the lowest requested over HEATUP seconds
|
||||||
|
#define HEATUP 5
|
||||||
|
|
||||||
|
// Fan speed is the highest HEATUP speed over COOLDOWN seconds
|
||||||
|
#define COOLDOWN 10
|
||||||
|
|
||||||
// Tjunction = 100C for i7-8565U (and probably the same for all WHL-U)
|
// Tjunction = 100C for i7-8565U (and probably the same for all WHL-U)
|
||||||
#define T_JUNCTION 100
|
#define T_JUNCTION 100
|
||||||
|
|
||||||
@ -30,7 +36,7 @@ struct FanPoint __code FAN_POINTS[] = {
|
|||||||
FAN_POINT(70, 45),
|
FAN_POINT(70, 45),
|
||||||
FAN_POINT(75, 55),
|
FAN_POINT(75, 55),
|
||||||
FAN_POINT(80, 75),
|
FAN_POINT(80, 75),
|
||||||
FAN_POINT(84, 100),
|
FAN_POINT(84, 100)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get duty cycle based on temperature, adapted from
|
// Get duty cycle based on temperature, adapted from
|
||||||
@ -51,12 +57,14 @@ uint8_t fan_duty(int16_t temp) {
|
|||||||
|
|
||||||
// If in between current temp and previous temp, interpolate
|
// If in between current temp and previous temp, interpolate
|
||||||
if (temp > prev->temp) {
|
if (temp > prev->temp) {
|
||||||
int16_t dtemp = (cur->temp - prev->temp);
|
return prev->duty;
|
||||||
int16_t dduty = ((int16_t)cur->duty) - ((int16_t)prev->duty);
|
|
||||||
return (uint8_t)(
|
// int16_t dtemp = (cur->temp - prev->temp);
|
||||||
((int16_t)prev->duty) +
|
// int16_t dduty = ((int16_t)cur->duty) - ((int16_t)prev->duty);
|
||||||
((temp - prev->temp) * dduty) / dtemp
|
// return (uint8_t)(
|
||||||
);
|
// ((int16_t)prev->duty) +
|
||||||
|
// ((temp - prev->temp) * dduty) / dtemp
|
||||||
|
// );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -66,6 +74,40 @@ uint8_t fan_duty(int16_t temp) {
|
|||||||
return PWM_DUTY(100);
|
return PWM_DUTY(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t fan_heatup(uint8_t duty) {
|
||||||
|
static uint8_t history[HEATUP] = { 0 };
|
||||||
|
uint8_t lowest = duty;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for (i = 0; (i + 1) < ARRAY_SIZE(history); i++) {
|
||||||
|
uint8_t value = history[i + 1];
|
||||||
|
if (value < lowest) {
|
||||||
|
lowest = value;
|
||||||
|
}
|
||||||
|
history[i] = value;
|
||||||
|
}
|
||||||
|
history[i] = duty;
|
||||||
|
|
||||||
|
return lowest;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t fan_cooldown(uint8_t duty) {
|
||||||
|
static uint8_t history[COOLDOWN] = { 0 };
|
||||||
|
uint8_t highest = duty;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for (i = 0; (i + 1) < ARRAY_SIZE(history); i++) {
|
||||||
|
uint8_t value = history[i + 1];
|
||||||
|
if (value > highest) {
|
||||||
|
highest = value;
|
||||||
|
}
|
||||||
|
history[i] = value;
|
||||||
|
}
|
||||||
|
history[i] = duty;
|
||||||
|
|
||||||
|
return highest;
|
||||||
|
}
|
||||||
|
|
||||||
void peci_init(void) {
|
void peci_init(void) {
|
||||||
// Allow PECI pin to be used
|
// Allow PECI pin to be used
|
||||||
GCR2 |= (1 << 4);
|
GCR2 |= (1 << 4);
|
||||||
@ -123,8 +165,10 @@ void peci_event(void) {
|
|||||||
peci_duty = PWM_DUTY(0);
|
peci_duty = PWM_DUTY(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (peci_duty != DCR2) {
|
uint8_t heatup_duty = fan_heatup(peci_duty);
|
||||||
DCR2 = peci_duty;
|
uint8_t cooldown_duty = fan_cooldown(heatup_duty);
|
||||||
DEBUG("PECI offset=%d, temp=%d = %d\n", peci_offset, peci_temp, peci_duty);
|
if (cooldown_duty != DCR2) {
|
||||||
|
DCR2 = cooldown_duty;
|
||||||
|
DEBUG("PECI offset=%d, temp=%d = %d\n", peci_offset, peci_temp, cooldown_duty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -383,11 +383,10 @@ void power_event(void) {
|
|||||||
// state is S3
|
// state is S3
|
||||||
static bool ack_last = false;
|
static bool ack_last = false;
|
||||||
bool ack_new = gpio_get(&SUSWARN_N);
|
bool ack_new = gpio_get(&SUSWARN_N);
|
||||||
|
#if LEVEL >= LEVEL_DEBUG
|
||||||
if (ack_new && !ack_last) {
|
if (ack_new && !ack_last) {
|
||||||
DEBUG("%02X: SUSPWRDNACK asserted\n", main_cycle);
|
DEBUG("%02X: SUSPWRDNACK asserted\n", main_cycle);
|
||||||
}
|
} else if (!ack_new && ack_last) {
|
||||||
#if LEVEL >= LEVEL_DEBUG
|
|
||||||
else if (!ack_new && ack_last) {
|
|
||||||
DEBUG("%02X: SUSPWRDNACK de-asserted\n", main_cycle);
|
DEBUG("%02X: SUSPWRDNACK de-asserted\n", main_cycle);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include <common/command.h>
|
#include <common/command.h>
|
||||||
#include <common/macro.h>
|
#include <common/macro.h>
|
||||||
#include <common/version.h>
|
#include <common/version.h>
|
||||||
|
#include <ec/pwm.h>
|
||||||
|
|
||||||
// Shared memory host semaphore
|
// Shared memory host semaphore
|
||||||
volatile uint8_t __xdata __at(0x1022) SMHSR;
|
volatile uint8_t __xdata __at(0x1022) SMHSR;
|
||||||
@ -143,6 +144,30 @@ static enum Result cmd_reset(void) {
|
|||||||
return RES_ERR;
|
return RES_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static enum Result cmd_fan_get(void) {
|
||||||
|
// If setting fan 0
|
||||||
|
if (smfi_cmd[2] == 0) {
|
||||||
|
// Get duty of fan 0
|
||||||
|
smfi_cmd[3] = DCR2;
|
||||||
|
return RES_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Failed if fan not found
|
||||||
|
return RES_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum Result cmd_fan_set(void) {
|
||||||
|
// If setting fan 0
|
||||||
|
if (smfi_cmd[2] == 0) {
|
||||||
|
// Set duty cycle of fan 0
|
||||||
|
DCR2 = smfi_cmd[3];
|
||||||
|
return RES_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Failed if fan not found
|
||||||
|
return RES_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
void smfi_event(void) {
|
void smfi_event(void) {
|
||||||
if (smfi_cmd[0]) {
|
if (smfi_cmd[0]) {
|
||||||
switch (smfi_cmd[0]) {
|
switch (smfi_cmd[0]) {
|
||||||
@ -174,6 +199,14 @@ void smfi_event(void) {
|
|||||||
case CMD_RESET:
|
case CMD_RESET:
|
||||||
smfi_cmd[1] = cmd_reset();
|
smfi_cmd[1] = cmd_reset();
|
||||||
break;
|
break;
|
||||||
|
#ifndef __SCRATCH__
|
||||||
|
case CMD_FAN_GET:
|
||||||
|
smfi_cmd[1] = cmd_fan_get();
|
||||||
|
break;
|
||||||
|
case CMD_FAN_SET:
|
||||||
|
smfi_cmd[1] = cmd_fan_set();
|
||||||
|
break;
|
||||||
|
#endif // __SCRATCH__
|
||||||
default:
|
default:
|
||||||
// Command not found
|
// Command not found
|
||||||
smfi_cmd[1] = RES_ERR;
|
smfi_cmd[1] = RES_ERR;
|
||||||
|
@ -7,6 +7,12 @@
|
|||||||
#include <ec/gpio.h>
|
#include <ec/gpio.h>
|
||||||
#include <ec/pwm.h>
|
#include <ec/pwm.h>
|
||||||
|
|
||||||
|
// Fan speed is the lowest requested over HEATUP seconds
|
||||||
|
#define HEATUP 5
|
||||||
|
|
||||||
|
// Fan speed is the highest HEATUP speed over COOLDOWN seconds
|
||||||
|
#define COOLDOWN 10
|
||||||
|
|
||||||
// Tjunction = 100C for i7-8565U (and probably the same for all WHL-U)
|
// Tjunction = 100C for i7-8565U (and probably the same for all WHL-U)
|
||||||
#define T_JUNCTION 100
|
#define T_JUNCTION 100
|
||||||
|
|
||||||
@ -30,7 +36,7 @@ struct FanPoint __code FAN_POINTS[] = {
|
|||||||
FAN_POINT(70, 45),
|
FAN_POINT(70, 45),
|
||||||
FAN_POINT(75, 55),
|
FAN_POINT(75, 55),
|
||||||
FAN_POINT(80, 75),
|
FAN_POINT(80, 75),
|
||||||
FAN_POINT(84, 100),
|
FAN_POINT(84, 100)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get duty cycle based on temperature, adapted from
|
// Get duty cycle based on temperature, adapted from
|
||||||
@ -51,12 +57,14 @@ uint8_t fan_duty(int16_t temp) {
|
|||||||
|
|
||||||
// If in between current temp and previous temp, interpolate
|
// If in between current temp and previous temp, interpolate
|
||||||
if (temp > prev->temp) {
|
if (temp > prev->temp) {
|
||||||
int16_t dtemp = (cur->temp - prev->temp);
|
return prev->duty;
|
||||||
int16_t dduty = ((int16_t)cur->duty) - ((int16_t)prev->duty);
|
|
||||||
return (uint8_t)(
|
// int16_t dtemp = (cur->temp - prev->temp);
|
||||||
((int16_t)prev->duty) +
|
// int16_t dduty = ((int16_t)cur->duty) - ((int16_t)prev->duty);
|
||||||
((temp - prev->temp) * dduty) / dtemp
|
// return (uint8_t)(
|
||||||
);
|
// ((int16_t)prev->duty) +
|
||||||
|
// ((temp - prev->temp) * dduty) / dtemp
|
||||||
|
// );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -66,6 +74,40 @@ uint8_t fan_duty(int16_t temp) {
|
|||||||
return PWM_DUTY(100);
|
return PWM_DUTY(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t fan_heatup(uint8_t duty) {
|
||||||
|
static uint8_t history[HEATUP] = { 0 };
|
||||||
|
uint8_t lowest = duty;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for (i = 0; (i + 1) < ARRAY_SIZE(history); i++) {
|
||||||
|
uint8_t value = history[i + 1];
|
||||||
|
if (value < lowest) {
|
||||||
|
lowest = value;
|
||||||
|
}
|
||||||
|
history[i] = value;
|
||||||
|
}
|
||||||
|
history[i] = duty;
|
||||||
|
|
||||||
|
return lowest;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t fan_cooldown(uint8_t duty) {
|
||||||
|
static uint8_t history[COOLDOWN] = { 0 };
|
||||||
|
uint8_t highest = duty;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for (i = 0; (i + 1) < ARRAY_SIZE(history); i++) {
|
||||||
|
uint8_t value = history[i + 1];
|
||||||
|
if (value > highest) {
|
||||||
|
highest = value;
|
||||||
|
}
|
||||||
|
history[i] = value;
|
||||||
|
}
|
||||||
|
history[i] = duty;
|
||||||
|
|
||||||
|
return highest;
|
||||||
|
}
|
||||||
|
|
||||||
void peci_init(void) {
|
void peci_init(void) {
|
||||||
// Allow PECI pin to be used
|
// Allow PECI pin to be used
|
||||||
GCR2 |= (1 << 4);
|
GCR2 |= (1 << 4);
|
||||||
@ -123,8 +165,10 @@ void peci_event(void) {
|
|||||||
peci_duty = PWM_DUTY(0);
|
peci_duty = PWM_DUTY(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (peci_duty != DCR2) {
|
uint8_t heatup_duty = fan_heatup(peci_duty);
|
||||||
DCR2 = peci_duty;
|
uint8_t cooldown_duty = fan_cooldown(heatup_duty);
|
||||||
DEBUG("PECI offset=%d, temp=%d = %d\n", peci_offset, peci_temp, peci_duty);
|
if (cooldown_duty != DCR2) {
|
||||||
|
DCR2 = cooldown_duty;
|
||||||
|
DEBUG("PECI offset=%d, temp=%d = %d\n", peci_offset, peci_temp, cooldown_duty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -383,11 +383,10 @@ void power_event(void) {
|
|||||||
// state is S3
|
// state is S3
|
||||||
static bool ack_last = false;
|
static bool ack_last = false;
|
||||||
bool ack_new = gpio_get(&SUSWARN_N);
|
bool ack_new = gpio_get(&SUSWARN_N);
|
||||||
|
#if LEVEL >= LEVEL_DEBUG
|
||||||
if (ack_new && !ack_last) {
|
if (ack_new && !ack_last) {
|
||||||
DEBUG("%02X: SUSPWRDNACK asserted\n", main_cycle);
|
DEBUG("%02X: SUSPWRDNACK asserted\n", main_cycle);
|
||||||
}
|
} else if (!ack_new && ack_last) {
|
||||||
#if LEVEL >= LEVEL_DEBUG
|
|
||||||
else if (!ack_new && ack_last) {
|
|
||||||
DEBUG("%02X: SUSPWRDNACK de-asserted\n", main_cycle);
|
DEBUG("%02X: SUSPWRDNACK de-asserted\n", main_cycle);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include <common/command.h>
|
#include <common/command.h>
|
||||||
#include <common/macro.h>
|
#include <common/macro.h>
|
||||||
#include <common/version.h>
|
#include <common/version.h>
|
||||||
|
#include <ec/pwm.h>
|
||||||
|
|
||||||
// Shared memory host semaphore
|
// Shared memory host semaphore
|
||||||
volatile uint8_t __xdata __at(0x1022) SMHSR;
|
volatile uint8_t __xdata __at(0x1022) SMHSR;
|
||||||
@ -143,6 +144,30 @@ static enum Result cmd_reset(void) {
|
|||||||
return RES_ERR;
|
return RES_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static enum Result cmd_fan_get(void) {
|
||||||
|
// If setting fan 0
|
||||||
|
if (smfi_cmd[2] == 0) {
|
||||||
|
// Get duty of fan 0
|
||||||
|
smfi_cmd[3] = DCR2;
|
||||||
|
return RES_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Failed if fan not found
|
||||||
|
return RES_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum Result cmd_fan_set(void) {
|
||||||
|
// If setting fan 0
|
||||||
|
if (smfi_cmd[2] == 0) {
|
||||||
|
// Set duty cycle of fan 0
|
||||||
|
DCR2 = smfi_cmd[3];
|
||||||
|
return RES_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Failed if fan not found
|
||||||
|
return RES_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
void smfi_event(void) {
|
void smfi_event(void) {
|
||||||
if (smfi_cmd[0]) {
|
if (smfi_cmd[0]) {
|
||||||
switch (smfi_cmd[0]) {
|
switch (smfi_cmd[0]) {
|
||||||
@ -174,6 +199,14 @@ void smfi_event(void) {
|
|||||||
case CMD_RESET:
|
case CMD_RESET:
|
||||||
smfi_cmd[1] = cmd_reset();
|
smfi_cmd[1] = cmd_reset();
|
||||||
break;
|
break;
|
||||||
|
#ifndef __SCRATCH__
|
||||||
|
case CMD_FAN_GET:
|
||||||
|
smfi_cmd[1] = cmd_fan_get();
|
||||||
|
break;
|
||||||
|
case CMD_FAN_SET:
|
||||||
|
smfi_cmd[1] = cmd_fan_set();
|
||||||
|
break;
|
||||||
|
#endif // __SCRATCH__
|
||||||
default:
|
default:
|
||||||
// Command not found
|
// Command not found
|
||||||
smfi_cmd[1] = RES_ERR;
|
smfi_cmd[1] = RES_ERR;
|
||||||
|
@ -16,6 +16,10 @@ enum Command {
|
|||||||
CMD_SPI = 5,
|
CMD_SPI = 5,
|
||||||
// Reset EC
|
// Reset EC
|
||||||
CMD_RESET = 6,
|
CMD_RESET = 6,
|
||||||
|
// Get fan speeds
|
||||||
|
CMD_FAN_GET = 7,
|
||||||
|
// Set fan speeds
|
||||||
|
CMD_FAN_SET = 8,
|
||||||
//TODO
|
//TODO
|
||||||
};
|
};
|
||||||
|
|
||||||
|
BIN
tool/src/.ec.rs.swp
Normal file
BIN
tool/src/.ec.rs.swp
Normal file
Binary file not shown.
@ -19,12 +19,14 @@ pub enum Cmd {
|
|||||||
Print = 4,
|
Print = 4,
|
||||||
Spi = 5,
|
Spi = 5,
|
||||||
Reset = 6,
|
Reset = 6,
|
||||||
|
FanGet = 7,
|
||||||
|
FanSet = 8,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const CMD_SPI_FLAG_READ: u8 = (1 << 0);
|
pub const CMD_SPI_FLAG_READ: u8 = 1 << 0;
|
||||||
pub const CMD_SPI_FLAG_DISABLE: u8 = (1 << 1);
|
pub const CMD_SPI_FLAG_DISABLE: u8 = 1 << 1;
|
||||||
pub const CMD_SPI_FLAG_SCRATCH: u8 = (1 << 2);
|
pub const CMD_SPI_FLAG_SCRATCH: u8 = 1 << 2;
|
||||||
pub const CMD_SPI_FLAG_BACKUP: u8 = (1 << 3);
|
pub const CMD_SPI_FLAG_BACKUP: u8 = 1 << 3;
|
||||||
|
|
||||||
pub struct Ec<T: Timeout> {
|
pub struct Ec<T: Timeout> {
|
||||||
cmd: u16,
|
cmd: u16,
|
||||||
@ -181,6 +183,18 @@ impl<T: Timeout> Ec<T> {
|
|||||||
pub unsafe fn reset(&mut self) -> Result<(), Error> {
|
pub unsafe fn reset(&mut self) -> Result<(), Error> {
|
||||||
self.command(Cmd::Reset)
|
self.command(Cmd::Reset)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub unsafe fn fan_get(&mut self, index: u8) -> Result<u8, Error> {
|
||||||
|
self.write(2, index);
|
||||||
|
self.command(Cmd::FanGet)?;
|
||||||
|
Ok(self.read(3))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn fan_set(&mut self, index: u8, duty: u8) -> Result<(), Error> {
|
||||||
|
self.write(2, index);
|
||||||
|
self.write(3, duty);
|
||||||
|
self.command(Cmd::FanSet)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct EcSpi<'a, T: Timeout> {
|
pub struct EcSpi<'a, T: Timeout> {
|
||||||
|
@ -274,9 +274,33 @@ unsafe fn print(message: &[u8]) -> Result<(), Error> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe fn fan_get(index: u8) -> Result<(), Error> {
|
||||||
|
iopl();
|
||||||
|
|
||||||
|
let mut ec = Ec::new(
|
||||||
|
StdTimeout::new(Duration::new(1, 0)),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let duty = ec.fan_get(index)?;
|
||||||
|
println!("{}", duty);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn fan_set(index: u8, duty: u8) -> Result<(), Error> {
|
||||||
|
iopl();
|
||||||
|
|
||||||
|
let mut ec = Ec::new(
|
||||||
|
StdTimeout::new(Duration::new(1, 0)),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
ec.fan_set(index, duty)
|
||||||
|
}
|
||||||
|
|
||||||
fn usage() {
|
fn usage() {
|
||||||
eprintln!(" console");
|
eprintln!(" console");
|
||||||
eprintln!(" flash [file]");
|
eprintln!(" flash [file]");
|
||||||
|
eprintln!(" fan [index] <duty>");
|
||||||
eprintln!(" info");
|
eprintln!(" info");
|
||||||
eprintln!(" print [message]");
|
eprintln!(" print [message]");
|
||||||
}
|
}
|
||||||
@ -293,6 +317,40 @@ fn main() {
|
|||||||
process::exit(1);
|
process::exit(1);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"fan" => match args.next() {
|
||||||
|
Some(index_str) => match index_str.parse::<u8>() {
|
||||||
|
Ok(index) => match args.next() {
|
||||||
|
Some(duty_str) => match duty_str.parse::<u8>() {
|
||||||
|
Ok(duty) => match unsafe { fan_set(index, duty) } {
|
||||||
|
Ok(()) => (),
|
||||||
|
Err(err) => {
|
||||||
|
eprintln!("failed to set fan {} to {}: {:X?}", index, duty, err);
|
||||||
|
process::exit(1);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Err(err) => {
|
||||||
|
eprintln!("failed to parse '{}': {:X?}", duty_str, err);
|
||||||
|
process::exit(1);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
None => match unsafe { fan_get(index) } {
|
||||||
|
Ok(()) => (),
|
||||||
|
Err(err) => {
|
||||||
|
eprintln!("failed to get fan {}: {:X?}", index, err);
|
||||||
|
process::exit(1);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Err(err) => {
|
||||||
|
eprintln!("failed to parse '{}': {:X?}", index_str, err);
|
||||||
|
process::exit(1);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
eprintln!("no index provided");
|
||||||
|
process::exit(1);
|
||||||
|
},
|
||||||
|
},
|
||||||
"flash" => match args.next() {
|
"flash" => match args.next() {
|
||||||
Some(path) => match unsafe { flash(&path) } {
|
Some(path) => match unsafe { flash(&path) } {
|
||||||
Ok(()) => (),
|
Ok(()) => (),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user