summaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
authorTimothy Pearson <tpearson@raptorengineering.com>2017-08-27 16:20:38 -0500
committerTimothy Pearson <tpearson@raptorengineering.com>2017-08-27 16:20:38 -0500
commit84eea7fdc46dd76e84cafbf96813bc826d5e08ad (patch)
tree035d28afe18ce33231b956349d1a3a90ec763d60 /common
parente65a7944211c70f6b5cfb6cedd73cc31105319de (diff)
downloadast2050-yocto-openbmc-84eea7fdc46dd76e84cafbf96813bc826d5e08ad.zip
ast2050-yocto-openbmc-84eea7fdc46dd76e84cafbf96813bc826d5e08ad.tar.gz
Add initial support for the ASpeed 2050 and the ASUS KGPE-D16
Thermal management is functional but expects all fans to be attached Known issues: * BMC has been observed spontaneously rebooting after ~7-8 hours uptime with no logs and no console output. * While kcs has been implemented, the IPMI daemon is only functional enough to report chassis status.
Diffstat (limited to 'common')
-rw-r--r--common/recipes-core/fan-ctrl/fan-ctrl/Makefile8
-rw-r--r--common/recipes-core/fan-ctrl/fan-ctrl/fand.cpp413
-rw-r--r--common/recipes-core/fan-ctrl/fan-ctrl/platform_sensor_init.cpp138
-rw-r--r--common/recipes-core/fan-ctrl/fan-ctrl/w83795.cpp396
-rw-r--r--common/recipes-core/fan-ctrl/fan-ctrl/w83795.h223
-rw-r--r--common/recipes-core/fan-ctrl/fan-ctrl/watchdog.cpp25
-rw-r--r--common/recipes-core/fan-ctrl/fan-ctrl_0.1.bb6
-rw-r--r--common/recipes-utils/openbmc-gpio/files/ast2050_gpio_table.py220
-rw-r--r--common/recipes-utils/openbmc-gpio/openbmc-gpio_0.1.bb5
9 files changed, 1420 insertions, 14 deletions
diff --git a/common/recipes-core/fan-ctrl/fan-ctrl/Makefile b/common/recipes-core/fan-ctrl/fan-ctrl/Makefile
index da74a34..825fa53 100644
--- a/common/recipes-core/fan-ctrl/fan-ctrl/Makefile
+++ b/common/recipes-core/fan-ctrl/fan-ctrl/Makefile
@@ -1,3 +1,4 @@
+# Copyright 2017 Raptor Engineering, LLC
# Copyright 2014-present Facebook. All Rights Reserved.
#
# This program file is free software; you can redistribute it and/or modify it
@@ -15,12 +16,15 @@
# 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301 USA
-all: fand
+all: fand platform_sensor_init
fand: fand.cpp watchdog.cpp
$(CXX) $(CXXFLAGS) -pthread -o $@ $^ $(LDFLAGS)
+platform_sensor_init: platform_sensor_init.cpp w83795.cpp
+ $(CXX) $(CXXFLAGS) -pthread -o $@ $^ $(LDFLAGS)
+
.PHONY: clean
clean:
- rm -rf *.o fand
+ rm -rf *.o fand platform_sensor_init
diff --git a/common/recipes-core/fan-ctrl/fan-ctrl/fand.cpp b/common/recipes-core/fan-ctrl/fan-ctrl/fand.cpp
index ccfbdb1..a7ebfd6 100644
--- a/common/recipes-core/fan-ctrl/fan-ctrl/fand.cpp
+++ b/common/recipes-core/fan-ctrl/fan-ctrl/fand.cpp
@@ -1,6 +1,7 @@
/*
* fand
*
+ * Copyright 2017 Raptor Engineering, LLC
* Copyright 2014-present Facebook. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -43,10 +44,11 @@
/* XXX: Both CONFIG_WEDGE and CONFIG_WEDGE100 are defined for Wedge100 */
#if !defined(CONFIG_YOSEMITE) && !defined(CONFIG_WEDGE) && \
- !defined(CONFIG_WEDGE100)
+ !defined(CONFIG_WEDGE100) && !defined(CONFIG_ASUS)
#error "No hardware platform defined!"
#endif
-#if defined(CONFIG_YOSEMITE) && defined(CONFIG_WEDGE)
+#if (defined(CONFIG_YOSEMITE) && defined(CONFIG_WEDGE)) || \
+ (defined(CONFIG_ASUS) && defined(CONFIG_WEDGE))
#error "Two hardware platforms defined!"
#endif
@@ -66,6 +68,10 @@
#include <facebook/wedge_eeprom.h>
#endif
+#if defined(CONFIG_ASUS)
+#define CONFIG_SLOPPY_FANS 1
+#endif
+
#include "watchdog.h"
/* Sensor definitions */
@@ -77,6 +83,9 @@
#define INTERNAL_TEMPS(x) (x)
#define EXTERNAL_TEMPS(x) (x)
#define TOTAL_1S_SERVERS 4
+#elif defined(CONFIG_ASUS)
+#define INTERNAL_TEMPS(x) ((x) * 1000.0) // stored as C * 1000
+#define EXTERNAL_TEMPS(x) ((x) / 1000.0)
#endif
/*
@@ -93,6 +102,7 @@
#endif
#define BAD_TEMP INTERNAL_TEMPS(-60)
+#define BAD_VOLTAGE (-50)
#define BAD_READ_THRESHOLD 4 /* How many times can reads fail */
#define FAN_FAILURE_THRESHOLD 4 /* How many times can a fan fail */
@@ -162,10 +172,28 @@
#elif defined(CONFIG_YOSEMITE)
#define FAN_LED_RED "0"
#define FAN_LED_BLUE "1"
+
+#elif defined(CONFIG_ASUS)
+#define PWM_DIR "/sys/class/i2c-adapter/i2c-1/1-002f/"
+
+#define FAN_READ_RPM_FORMAT "fan%d_input"
+#define PWM_UNIT_MAX 255
+
+#define CHIPSET_TEMP_DEVICE PWM_DIR "temp1_input"
+#define CPU1_TEMP_DEVICE PWM_DIR "temp7_input"
+#define CPU2_TEMP_DEVICE PWM_DIR "temp8_input"
+#define CPU2_VCORE_DEVICE PWM_DIR "in1_input"
+
+#define MAIN_POWER_OFF_DIRECTION "/sys/class/gpio/gpio40/direction"
+#define MAIN_POWER_OFF_CTL "/sys/class/gpio/gpio40/value"
+
+#define FAN_LED_RED "1"
+#define FAN_LED_BLUE "0"
+
#endif
#if (defined(CONFIG_YOSEMITE) || defined(CONFIG_WEDGE)) && \
- !defined(CONFIG_WEDGE100)
+ !defined(CONFIG_WEDGE100) && !defined(CONFIG_ASUS)
#define PWM_DIR "/sys/devices/platform/ast_pwm_tacho.0"
#define PWM_UNIT_MAX 96
@@ -193,12 +221,17 @@ const char *fan_led[] = {FAN0_LED, FAN1_LED, FAN2_LED, FAN3_LED,
#define INTAKE_LIMIT INTERNAL_TEMPS(60)
#define SWITCH_LIMIT INTERNAL_TEMPS(80)
+#define CHIPSET_LIMIT INTERNAL_TEMPS(80)
#if defined(CONFIG_YOSEMITE)
#define USERVER_LIMIT INTERNAL_TEMPS(110)
#else
#define USERVER_LIMIT INTERNAL_TEMPS(90)
#endif
+#if defined(CONFIG_ASUS)
+#define CPU_LIMIT INTERNAL_TEMPS(110)
+#endif
+
#define TEMP_TOP INTERNAL_TEMPS(70)
#define TEMP_BOTTOM INTERNAL_TEMPS(40)
@@ -214,7 +247,7 @@ const char *fan_led[] = {FAN0_LED, FAN1_LED, FAN2_LED, FAN3_LED,
#define WEDGE_FAN_LOW 35
#define WEDGE_FAN_MEDIUM 50
#define WEDGE_FAN_HIGH 70
-#if defined(CONFIG_WEDGE100)
+#if defined(CONFIG_WEDGE100) || defined(CONFIG_ASUS)
#define WEDGE_FAN_MAX 100
#else
#define WEDGE_FAN_MAX 99
@@ -252,6 +285,11 @@ int fan_to_pwm_map[] = {0, 1};
// Tacho offset between front and rear fans:
#define REAR_FAN_OFFSET 1
+#elif defined(CONFIG_ASUS)
+int fan_to_rpm_map[] = {1, 2, 3, 4, 5, 6, 7, 8};
+int fan_to_pwm_map[] = {1, 1, 2, 2, 2, 2, 2, 2}; // 1 == 4 pin fans, 2 == 3 pin fans
+#define FANS 8
+
#endif
@@ -364,6 +402,47 @@ struct rpm_to_pct_map *rpm_rear_map = rpm_map;
#define FRONT_MAP_SIZE MAP_SIZE
#define REAR_MAP_SIZE MAP_SIZE
+#elif defined(CONFIG_ASUS)
+struct rpm_to_pct_map rpm_front_map[] = {{15, 1804},
+ {20, 1864},
+ {25, 2011},
+ {30, 2268},
+ {35, 2683},
+ {40, 3110},
+ {45, 3619},
+ {50, 4017},
+ {55, 4455},
+ {60, 4720},
+ {65, 5113},
+ {70, 5487},
+ {75, 5973},
+ {80, 6428},
+ {85, 6994},
+ {90, 7417},
+ {95, 7941},
+ {100, 8490}};
+#define FRONT_MAP_SIZE (sizeof(rpm_front_map) / sizeof(struct rpm_to_pct_map))
+
+struct rpm_to_pct_map rpm_rear_map[] = {{15, 450},
+ {20, 600},
+ {25, 750},
+ {30, 900},
+ {35, 1050},
+ {40, 1200},
+ {45, 1350},
+ {50, 1500},
+ {55, 1550},
+ {60, 1600},
+ {65, 1650},
+ {70, 1700},
+ {75, 1750},
+ {80, 1800},
+ {85, 1850},
+ {90, 1900},
+ {95, 1950},
+ {100, 2000}};
+#define REAR_MAP_SIZE (sizeof(rpm_rear_map) / sizeof(struct rpm_to_pct_map))
+
#endif
/*
@@ -409,6 +488,45 @@ struct temp_to_pct_map cpu_map[] = {{-28, 10},
#define CPU_MAP_SIZE (sizeof(cpu_map) / sizeof(struct temp_to_pct_map))
#endif
+#if defined(CONFIG_ASUS)
+struct temp_to_pct_map chipset_map[] = {{30, 1},
+ {32, 5},
+ {35, 10},
+ {37, 15},
+ {40, 20},
+ {42, 25},
+ {45, 30},
+ {47, 35},
+ {50, 40},
+ {52, 45},
+ {55, 50},
+ {57, 55},
+ {60, 60},
+ {62, 65},
+ {65, 70},
+ {67, 80},
+ {70, 100}};
+#define CHIPSET_MAP_SIZE (sizeof(chipset_map) / sizeof(struct temp_to_pct_map))
+
+struct temp_to_pct_map cpu_map[] = {{38, 1},
+ {40, 5},
+ {42, 10},
+ {44, 15},
+ {46, 20},
+ {48, 25},
+ {50, 30},
+ {52, 35},
+ {54, 40},
+ {56, 45},
+ {58, 50},
+ {60, 55},
+ {62, 60},
+ {64, 65},
+ {66, 70},
+ {68, 80},
+ {70, 100}};
+#define CPU_MAP_SIZE (sizeof(cpu_map) / sizeof(struct temp_to_pct_map))
+#endif
#define FAN_FAILURE_OFFSET 30
@@ -425,6 +543,14 @@ int temp_top = TEMP_TOP;
int report_temp = REPORT_TEMP;
bool verbose = false;
+#if defined(CONFIG_WEDGE)
+ int cpu2_installed = 0;
+#elif defined(CONFIG_ASUS)
+ int cpu2_installed = 1;
+#else
+ int cpu2_installed = 0;
+#endif
+
void usage() {
fprintf(stderr,
"fand [-v] [-l <low-pct>] [-m <medium-pct>] "
@@ -510,6 +636,28 @@ int read_temp(const char *device, int *value) {
}
#endif
+#if defined(CONFIG_ASUS)
+int read_temp(const char *device, int *value) {
+ char full_name[LARGEST_DEVICE_NAME + 1];
+
+ /* We set an impossible value to check for errors */
+ *value = BAD_TEMP;
+ snprintf(
+ full_name, LARGEST_DEVICE_NAME, "%s", device);
+ return read_device(full_name, value);
+}
+#endif
+
+int read_voltage(const char *device, int *value) {
+ char full_name[LARGEST_DEVICE_NAME + 1];
+
+ /* We set an impossible value to check for errors */
+ *value = BAD_VOLTAGE;
+ snprintf(
+ full_name, LARGEST_DEVICE_NAME, "%s", device);
+ return read_device(full_name, value);
+}
+
#if defined(CONFIG_WEDGE) && !defined(CONFIG_WEDGE100)
int read_gpio_value(const int id, const char *device, int *value) {
char full_name[LARGEST_DEVICE_NAME];
@@ -644,6 +792,9 @@ int fan_rpm_to_pct(const struct rpm_to_pct_map *table,
}
int fan_speed_okay(const int fan, const int speed, const int slop) {
+#if defined(CONFIG_ASUS)
+ int real_fan_speed;
+#endif
int front_fan, rear_fan;
int front_pct, rear_pct;
int real_fan;
@@ -656,6 +807,17 @@ int fan_speed_okay(const int fan, const int speed, const int slop) {
real_fan = fan_to_rpm_map[fan];
+#if defined(CONFIG_ASUS)
+ real_fan_speed = 0;
+ read_fan_value(real_fan, FAN_READ_RPM_FORMAT, &real_fan_speed);
+ if (fan < 2) {
+ front_pct = fan_rpm_to_pct(rpm_front_map, FRONT_MAP_SIZE, real_fan_speed);
+ }
+ else {
+ front_pct = fan_rpm_to_pct(rpm_rear_map, REAR_MAP_SIZE, real_fan_speed);
+ }
+ front_fan = real_fan_speed;
+#else
front_fan = 0;
read_fan_value(real_fan, FAN_READ_RPM_FORMAT, &front_fan);
front_pct = fan_rpm_to_pct(rpm_front_map, FRONT_MAP_SIZE, front_fan);
@@ -664,7 +826,7 @@ int fan_speed_okay(const int fan, const int speed, const int slop) {
read_fan_value(real_fan + REAR_FAN_OFFSET, FAN_READ_RPM_FORMAT, &rear_fan);
rear_pct = fan_rpm_to_pct(rpm_rear_map, REAR_MAP_SIZE, rear_fan);
#endif
-
+#endif
/*
* If the fans are broken, the measured rate will be rather
@@ -683,6 +845,13 @@ int fan_speed_okay(const int fan, const int speed, const int slop) {
okay = (abs(front_pct - speed) * 100 / speed < slop);
#endif
+#if defined(CONFIG_SLOPPY_FANS)
+ // Don't alert if fan is spinning faster than expected...
+ if (!okay && (front_pct > speed)) {
+ okay = 1;
+ }
+#endif
+
if (!okay || verbose) {
syslog(!okay ? LOG_WARNING : LOG_INFO,
#ifdef BACK_TO_BACK_FANS
@@ -703,6 +872,10 @@ int fan_speed_okay(const int fan, const int speed, const int slop) {
return okay;
}
+#if defined(CONFIG_ASUS)
+int averaged_pwm_values[2] = {0, 0};
+#endif
+
/* Set fan speed as a percentage */
int write_fan_speed(const int fan, const int value) {
@@ -717,16 +890,60 @@ int write_fan_speed(const int fan, const int value) {
if (value == 0) {
#if defined(CONFIG_WEDGE100)
return write_fan_value(real_fan, "fantray%d_pwm", 0);
+#elif defined(CONFIG_ASUS)
+ return write_fan_value(real_fan, "pwm%d_enable", 0);
#else
return write_fan_value(real_fan, "pwm%d_en", 0);
#endif
} else {
- int unit = value * PWM_UNIT_MAX / 100;
+ int unit = (value * PWM_UNIT_MAX) / 100;
int status;
+#if defined(CONFIG_ASUS)
+ // The KGPE-D16 / KCMA-D8 only has two fan outputs; one controls all 4 pin fans,
+ // and the other controls all 3 pin fans. Average the requested PWM values
+ // as a middle-of-the-road thermal strategy...
+ if (fan == 0) {
+ if (cpu2_installed) {
+ averaged_pwm_values[0] = unit;
+ return 0;
+ }
+ }
+ else if (fan == 1) {
+ if (cpu2_installed) {
+ averaged_pwm_values[0] += unit;
+ averaged_pwm_values[0] /= 2;
+ unit = averaged_pwm_values[0];
+ }
+ else {
+ return 0;
+ }
+ }
+ else if (fan == 2) {
+ averaged_pwm_values[1] = unit;
+ return 0;
+ }
+ else if ((fan > 2) && (fan < 7)) {
+ averaged_pwm_values[1] += unit;
+ return 0;
+ }
+ else if (fan == 7) {
+ averaged_pwm_values[1] += unit;
+ averaged_pwm_values[1] /= 6;
+ unit = averaged_pwm_values[1];
+ }
+#endif
+
#if defined(CONFIG_WEDGE100)
// Note that PWM for Wedge100 is in 32nds of a cycle
return write_fan_value(real_fan, "fantray%d_pwm", unit);
+#elif defined(CONFIG_ASUS)
+ if ((status = write_fan_value(real_fan, "pwm%d_enable", 1)) != 0) {
+ return status;
+ }
+ if ((status = write_fan_value(real_fan, "pwm%d", unit)) != 0) {
+ return status;
+ }
#else
if (unit == PWM_UNIT_MAX)
unit = 0;
@@ -741,7 +958,7 @@ int write_fan_speed(const int fan, const int value) {
}
}
-#if defined(CONFIG_YOSEMITE)
+#if defined(CONFIG_YOSEMITE) || defined(CONFIG_ASUS)
int temp_to_fan_speed(int temp, struct temp_to_pct_map *map, int map_size) {
int i = map_size - 1;
@@ -796,11 +1013,17 @@ int server_shutdown(const char *why) {
system("rmmod adm1275");
system("i2cset -y 12 0x10 0x01 00");
}
+#elif defined(CONFIG_ASUS)
+ write_device(MAIN_POWER_OFF_DIRECTION, "out");
+ write_device(MAIN_POWER_OFF_CTL, "0");
+ sleep(1);
+ write_device(MAIN_POWER_OFF_CTL, "1");
#else
// TODO(7088822): try throttling, then shutting down server.
syslog(LOG_EMERG, "Need to implement actual shutdown!\n");
#endif
+#if !defined(CONFIG_ASUS)
/*
* We have to stop the watchdog, or the system will be automatically
* rebooted some seconds after fand exits (and stops kicking the
@@ -811,6 +1034,7 @@ int server_shutdown(const char *why) {
sleep(2);
exit(2);
+#endif
}
/* Gracefully shut down on receipt of a signal */
@@ -837,6 +1061,11 @@ int main(int argc, char **argv) {
int exhaust_temp;
int switch_temp;
int userver_temp;
+#elif defined(CONFIG_ASUS)
+ int chipset_temp;
+ int cpu1_temp;
+ int cpu2_temp;
+ int cpu2_vcore_mv;
#else
float intake_temp;
float exhaust_temp;
@@ -849,6 +1078,13 @@ int main(int argc, char **argv) {
int fan_speed_changes = 0;
int old_speed;
+ int cpu_fan_speed = fan_high;
+ int chassis_fan_speed = fan_high;
+ int cpu_fan_speed_changes = 0;
+ int chassis_fan_speed_changes = 0;
+ int cpu_old_speed = fan_high;
+ int chassis_old_speed = fan_high;
+
int fan_bad[FANS];
int fan;
@@ -942,6 +1178,9 @@ int main(int argc, char **argv) {
}
for (fan = 0; fan < total_fans; fan++) {
+ if (!cpu2_installed && (fan == 1)) {
+ continue;
+ }
fan_bad[fan] = 0;
write_fan_speed(fan + fan_offset, fan_speed);
write_fan_led(fan + fan_offset, FAN_LED_BLUE);
@@ -980,6 +1219,8 @@ int main(int argc, char **argv) {
while (1) {
int max_temp;
old_speed = fan_speed;
+ cpu_old_speed = cpu_fan_speed;
+ chassis_old_speed = chassis_fan_speed;
/* Read sensors */
@@ -998,6 +1239,31 @@ int main(int argc, char **argv) {
switch_temp == BAD_TEMP)) {
bad_reads++;
}
+#elif defined(CONFIG_ASUS)
+ read_temp(CHIPSET_TEMP_DEVICE, &chipset_temp);
+ read_temp(CPU1_TEMP_DEVICE, &cpu1_temp);
+ read_temp(CPU2_TEMP_DEVICE, &cpu2_temp);
+ read_voltage(CPU2_VCORE_DEVICE, &cpu2_vcore_mv);
+
+ /*
+ * uServer can be powered down, but all of the rest of the sensors
+ * should be readable at any time.
+ */
+
+ if ((chipset_temp == BAD_TEMP) || (cpu1_temp == BAD_TEMP) ||
+ (cpu2_temp == BAD_TEMP) || (cpu2_vcore_mv == BAD_VOLTAGE)) {
+ bad_reads++;
+ }
+ else {
+ bad_reads = 0; // Only care about continuous bad reads
+ }
+
+ if (cpu2_vcore_mv == 0) {
+ cpu2_installed = 0;
+ }
+ else {
+ cpu2_installed = 1;
+ }
#else
intake_temp = exhaust_temp = userver_temp = BAD_TEMP;
if (yosemite_sensor_read(FRU_SPB, SP_SENSOR_INLET_TEMP, &intake_temp) ||
@@ -1025,8 +1291,51 @@ int main(int argc, char **argv) {
if (bad_reads > BAD_READ_THRESHOLD) {
server_shutdown("Some sensors couldn't be read");
+ bad_reads = 0;
+ kick_watchdog();
+ continue;
}
+#if defined(CONFIG_ASUS)
+ if (log_count++ % report_temp == 0) {
+ syslog(LOG_DEBUG,
+ "Temp chipset %f, CPU1 %f, CPU2 %f, "
+ "CPU fan speed %d, CPU speed changes %d"
+ "chassis fan speed %d, chassis speed changes %d",
+ EXTERNAL_TEMPS((float)chipset_temp),
+ EXTERNAL_TEMPS((float)cpu1_temp),
+ EXTERNAL_TEMPS((float)cpu2_temp),
+ cpu_fan_speed,
+ cpu_fan_speed_changes,
+ chassis_fan_speed,
+ chassis_fan_speed_changes);
+ }
+
+ /* Protection heuristics */
+
+ if (chipset_temp > CHIPSET_LIMIT) {
+ server_shutdown("Chipset temp limit reached");
+ bad_reads = 0;
+ kick_watchdog();
+ continue;
+ }
+
+ if (cpu1_temp > CPU_LIMIT) {
+ server_shutdown("CPU1 temp limit reached");
+ bad_reads = 0;
+ kick_watchdog();
+ continue;
+ }
+
+ if (cpu2_installed) {
+ if (cpu2_temp > CPU_LIMIT) {
+ server_shutdown("CPU2 temp limit reached");
+ bad_reads = 0;
+ kick_watchdog();
+ continue;
+ }
+ }
+#else
if (log_count++ % report_temp == 0) {
syslog(LOG_DEBUG,
#if defined(CONFIG_WEDGE) || defined(CONFIG_WEDGE100)
@@ -1051,17 +1360,27 @@ int main(int argc, char **argv) {
if (intake_temp > INTAKE_LIMIT) {
server_shutdown("Intake temp limit reached");
+ bad_reads = 0;
+ kick_watchdog();
+ continue;
}
#if defined(CONFIG_WEDGE) || defined(CONFIG_WEDGE100)
if (switch_temp > SWITCH_LIMIT) {
server_shutdown("T2 temp limit reached");
+ bad_reads = 0;
+ kick_watchdog();
+ continue;
}
#endif
if (userver_temp + USERVER_TEMP_FUDGE > USERVER_LIMIT) {
server_shutdown("uServer temp limit reached");
+ bad_reads = 0;
+ kick_watchdog();
+ continue;
}
+#endif
/*
* Calculate change needed -- we should eventually
@@ -1085,9 +1404,31 @@ int main(int argc, char **argv) {
} else {
fan_speed = cpu_speed;
}
+#elif defined(CONFIG_ASUS)
+ int max_cpu_temp = cpu1_temp + USERVER_TEMP_FUDGE;
+
+ if (cpu2_installed) {
+ if (cpu2_temp + USERVER_TEMP_FUDGE > max_cpu_temp) {
+ max_cpu_temp = cpu2_temp + USERVER_TEMP_FUDGE;
+ }
+ }
+
+ int chassis_speed = temp_to_fan_speed(EXTERNAL_TEMPS(chipset_temp), chipset_map,
+ CHIPSET_MAP_SIZE);
+ int cpu_speed = temp_to_fan_speed(EXTERNAL_TEMPS(max_cpu_temp), cpu_map, CPU_MAP_SIZE);
+
+ if (cpu_fan_speed == fan_max && fan_failure != 0) {
+ /* Don't change a thing */
+ } else {
+ cpu_fan_speed = cpu_speed;
+ }
+ if (chassis_fan_speed == fan_max && fan_failure != 0) {
+ /* Don't change a thing */
+ } else {
+ chassis_fan_speed = chassis_speed;
+ }
#else
/* Other systems use a simpler built-in table to determine fan speed. */
-
if (switch_temp > userver_temp + USERVER_TEMP_FUDGE) {
max_temp = switch_temp;
} else {
@@ -1125,6 +1466,31 @@ int main(int argc, char **argv) {
* earlier, all remaining fans should continue to run at max speed.
*/
+#if defined(CONFIG_ASUS)
+ if (fan_failure == 0 && cpu_fan_speed != cpu_old_speed) {
+ syslog(LOG_NOTICE,
+ "CPU fan speed changing from %d to %d",
+ cpu_old_speed,
+ cpu_fan_speed);
+ cpu_fan_speed_changes++;
+ }
+ if (fan_failure == 0 && chassis_fan_speed != chassis_old_speed) {
+ syslog(LOG_NOTICE,
+ "Chassis fan speed changing from %d to %d",
+ chassis_old_speed,
+ chassis_fan_speed);
+ chassis_fan_speed_changes++;
+ }
+ for (fan = 0; fan < 2; fan++) {
+ if (!cpu2_installed && (fan == 1)) {
+ continue;
+ }
+ write_fan_speed(fan + fan_offset, cpu_fan_speed);
+ }
+ for (fan = 2; fan < total_fans; fan++) {
+ write_fan_speed(fan + fan_offset, chassis_fan_speed);
+ }
+#else
if (fan_failure == 0 && fan_speed != old_speed) {
syslog(LOG_NOTICE,
"Fan speed changing from %d to %d",
@@ -1132,9 +1498,13 @@ int main(int argc, char **argv) {
fan_speed);
fan_speed_changes++;
for (fan = 0; fan < total_fans; fan++) {
+ if (!cpu2_installed && (fan == 1)) {
+ continue;
+ }
write_fan_speed(fan + fan_offset, fan_speed);
}
}
+#endif
/*
* Wait for some change. Typical I2C temperature sensors
@@ -1150,11 +1520,22 @@ int main(int argc, char **argv) {
/* Check fan RPMs */
for (fan = 0; fan < total_fans; fan++) {
+ if (!cpu2_installed && (fan == 1)) {
+ continue;
+ }
/*
* Make sure that we're within some percentage
* of the requested speed.
*/
+#if defined(CONFIG_ASUS)
+ int desired_fan_speed = cpu_fan_speed;
+ if (fan > 1) {
+ desired_fan_speed = chassis_fan_speed;
+ }
+ if (fan_speed_okay(fan + fan_offset, desired_fan_speed, FAN_FAILURE_OFFSET)) {
+#else
if (fan_speed_okay(fan + fan_offset, fan_speed, FAN_FAILURE_OFFSET)) {
+#endif
if (fan_bad[fan] > FAN_FAILURE_THRESHOLD) {
write_fan_led(fan + fan_offset, FAN_LED_BLUE);
syslog(LOG_CRIT,
@@ -1169,6 +1550,9 @@ int main(int argc, char **argv) {
fan_failure = 0;
for (fan = 0; fan < total_fans; fan++) {
+ if (!cpu2_installed && (fan == 1)) {
+ continue;
+ }
if (fan_bad[fan] > FAN_FAILURE_THRESHOLD) {
fan_failure++;
write_fan_led(fan + fan_offset, FAN_LED_RED);
@@ -1190,8 +1574,13 @@ int main(int argc, char **argv) {
*/
fan_speed = fan_max;
+ cpu_fan_speed = fan_max;
+ chassis_fan_speed = fan_max;
for (fan = 0; fan < total_fans; fan++) {
- write_fan_speed(fan + fan_offset, fan_speed);
+ if (!cpu2_installed && (fan == 1)) {
+ continue;
+ }
+ write_fan_speed(fan + fan_offset, fan_max);
}
#if defined(CONFIG_WEDGE) || defined(CONFIG_WEDGE100)
@@ -1206,11 +1595,17 @@ int main(int argc, char **argv) {
if (fan_failure == total_fans) {
int count = 0;
for (fan = 0; fan < total_fans; fan++) {
+ if (!cpu2_installed && (fan == 1)) {
+ continue;
+ }
if (fan_bad[fan] > FAN_SHUTDOWN_THRESHOLD)
count++;
}
if (count == total_fans) {
server_shutdown("all fans are bad for more than 12 cycles");
+ bad_reads = 0;
+ kick_watchdog();
+ continue;
}
}
#endif
diff --git a/common/recipes-core/fan-ctrl/fan-ctrl/platform_sensor_init.cpp b/common/recipes-core/fan-ctrl/fan-ctrl/platform_sensor_init.cpp
new file mode 100644
index 0000000..512bca0
--- /dev/null
+++ b/common/recipes-core/fan-ctrl/fan-ctrl/platform_sensor_init.cpp
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2017 Raptor Engineering
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <linux/i2c-dev.h>
+
+#include "w83795.h"
+
+#define I2C_BUS_DEVICE_NODE "/dev/i2c-1"
+#define I2C_SLAVE_DEVICE_ADDR 0x2f
+
+int smbus_fd = -1;
+
+int main() {
+ struct drivers_i2c_w83795_config platform_configuration;
+
+ // ASUS KGPE-D16
+ platform_configuration.fanin_ctl1 = 0xff;
+ platform_configuration.fanin_ctl2 = 0x00;
+ platform_configuration.temp_ctl1 = 0x2a;
+ platform_configuration.temp_ctl2 = 0x01;
+ platform_configuration.temp_dtse = 0x03;
+ platform_configuration.volt_ctl1 = 0xff;
+ platform_configuration.volt_ctl2 = 0xf7;
+ platform_configuration.temp1_fan_select = 0x00;
+ platform_configuration.temp2_fan_select = 0x00;
+ platform_configuration.temp3_fan_select = 0x00;
+ platform_configuration.temp4_fan_select = 0x00;
+ platform_configuration.temp5_fan_select = 0x00;
+ platform_configuration.temp6_fan_select = 0x00;
+ platform_configuration.temp1_source_select = 0x00;
+ platform_configuration.temp2_source_select = 0x00;
+ platform_configuration.temp3_source_select = 0x00;
+ platform_configuration.temp4_source_select = 0x00;
+ platform_configuration.temp5_source_select = 0x00;
+ platform_configuration.temp6_source_select = 0x00;
+ platform_configuration.tr1_critical_temperature = 85;
+ platform_configuration.tr1_critical_hysteresis = 80;
+ platform_configuration.tr1_warning_temperature = 70;
+ platform_configuration.tr1_warning_hysteresis = 65;
+ platform_configuration.dts_critical_temperature = 85;
+ platform_configuration.dts_critical_hysteresis = 80;
+ platform_configuration.dts_warning_temperature = 70;
+ platform_configuration.dts_warning_hysteresis = 65;
+ platform_configuration.temp1_critical_temperature = 80;
+ platform_configuration.temp2_critical_temperature = 80;
+ platform_configuration.temp3_critical_temperature = 80;
+ platform_configuration.temp4_critical_temperature = 80;
+ platform_configuration.temp5_critical_temperature = 80;
+ platform_configuration.temp6_critical_temperature = 80;
+ platform_configuration.temp1_target_temperature = 80;
+ platform_configuration.temp2_target_temperature = 80;
+ platform_configuration.temp3_target_temperature = 80;
+ platform_configuration.temp4_target_temperature = 80;
+ platform_configuration.temp5_target_temperature = 80;
+ platform_configuration.temp6_target_temperature = 80;
+ platform_configuration.fan1_nonstop = 7;
+ platform_configuration.fan2_nonstop = 7;
+ platform_configuration.fan3_nonstop = 7;
+ platform_configuration.fan4_nonstop = 7;
+ platform_configuration.fan5_nonstop = 7;
+ platform_configuration.fan6_nonstop = 7;
+ platform_configuration.fan7_nonstop = 7;
+ platform_configuration.fan8_nonstop = 7;
+ platform_configuration.default_speed = 100;
+ platform_configuration.fan1_duty = 100;
+ platform_configuration.fan2_duty = 100;
+ platform_configuration.fan3_duty = 100;
+ platform_configuration.fan4_duty = 100;
+ platform_configuration.fan5_duty = 100;
+ platform_configuration.fan6_duty = 100;
+ platform_configuration.fan7_duty = 100;
+ platform_configuration.fan8_duty = 100;
+ platform_configuration.vcore1_high_limit_mv = 1500;
+ platform_configuration.vcore1_low_limit_mv = 900;
+ platform_configuration.vcore2_high_limit_mv = 1500;
+ platform_configuration.vcore2_low_limit_mv = 900;
+ platform_configuration.vsen3_high_limit_mv = 1600;
+ platform_configuration.vsen3_low_limit_mv = 1100;
+ platform_configuration.vsen4_high_limit_mv = 1600;
+ platform_configuration.vsen4_low_limit_mv = 1100;
+ platform_configuration.vsen5_high_limit_mv = 1250;
+ platform_configuration.vsen5_low_limit_mv = 1150;
+ platform_configuration.vsen6_high_limit_mv = 1250;
+ platform_configuration.vsen6_low_limit_mv = 1150;
+ platform_configuration.vsen7_high_limit_mv = 1250;
+ platform_configuration.vsen7_low_limit_mv = 1050;
+ platform_configuration.vsen8_high_limit_mv = 1900;
+ platform_configuration.vsen8_low_limit_mv = 1700;
+ platform_configuration.vsen9_high_limit_mv = 1250;
+ platform_configuration.vsen9_low_limit_mv = 1150;
+ platform_configuration.vsen10_high_limit_mv = 1150;
+ platform_configuration.vsen10_low_limit_mv = 1050;
+ platform_configuration.vsen11_high_limit_mv = 1625;
+ platform_configuration.vsen11_low_limit_mv = 1500;
+ platform_configuration.vsen12_high_limit_mv = 1083;
+ platform_configuration.vsen12_low_limit_mv = 917;
+ platform_configuration.vsen13_high_limit_mv = 1625;
+ platform_configuration.vsen13_low_limit_mv = 1500;
+ platform_configuration.vdd_high_limit_mv = 3500;
+ platform_configuration.vdd_low_limit_mv = 3100;
+ platform_configuration.vsb_high_limit_mv = 3500;
+ platform_configuration.vsb_low_limit_mv = 3100;
+ platform_configuration.vbat_high_limit_mv = 3500;
+ platform_configuration.vbat_low_limit_mv = 2500;
+ platform_configuration.smbus_aux = 1;
+
+ smbus_fd = open(I2C_BUS_DEVICE_NODE, O_RDWR);
+ if (smbus_fd < 0) {
+ printf("Unable to open I2C device node %s for read/write!\n", I2C_BUS_DEVICE_NODE);
+ return 1;
+ }
+
+ if (ioctl(smbus_fd, I2C_SLAVE, I2C_SLAVE_DEVICE_ADDR) < 0) {
+ close(smbus_fd);
+ printf("Unable to set up communication with I2C device at address %02x!\n", I2C_SLAVE_DEVICE_ADDR);
+ return 1;
+ }
+
+ w83795_init(MANUAL_MODE, DTS_SRC_AMD_SBTSI, &platform_configuration);
+
+ close(smbus_fd);
+} \ No newline at end of file
diff --git a/common/recipes-core/fan-ctrl/fan-ctrl/w83795.cpp b/common/recipes-core/fan-ctrl/fan-ctrl/w83795.cpp
new file mode 100644
index 0000000..c327957
--- /dev/null
+++ b/common/recipes-core/fan-ctrl/fan-ctrl/w83795.cpp
@@ -0,0 +1,396 @@
+/*
+ * Copyright (C) 2012 Advanced Micro Devices, Inc.
+ * Copyright (C) 2015-2017 Raptor Engineering
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <sys/ioctl.h>
+#include <linux/i2c-dev.h>
+#include "w83795.h"
+
+#define BIOS_DEBUG 0
+#define BIOS_INFO 1
+#define BIOS_WARNING 2
+#define BIOS_ERR 3
+
+extern int smbus_fd;
+
+// =========================================================================================================================
+// Taken from lm-sensors
+// =========================================================================================================================
+#define I2C_SMBUS_READ 1
+#define I2C_SMBUS_WRITE 0
+#define I2C_SMBUS_BLOCK_MAX 32
+#define I2C_SMBUS_BYTE_DATA 2
+#define I2C_SMBUS 0x0720
+
+union i2c_smbus_data {
+ __u8 byte;
+ __u16 word;
+ __u8 block[I2C_SMBUS_BLOCK_MAX + 2];
+};
+
+static inline __s32 i2c_smbus_access(int file, char read_write, __u8 command, int size, union i2c_smbus_data *data) {
+ struct i2c_smbus_ioctl_data args;
+
+ args.read_write = read_write;
+ args.command = command;
+ args.size = size;
+ args.data = data;
+ return ioctl(file,I2C_SMBUS,&args);
+}
+
+static inline __s32 i2c_smbus_read_byte_data(int file, __u8 command)
+{
+ union i2c_smbus_data data;
+ if (i2c_smbus_access(file,I2C_SMBUS_READ,command, I2C_SMBUS_BYTE_DATA,&data))
+ return -1;
+ else
+ return 0x0ff & data.byte;
+}
+
+static inline __s32 i2c_smbus_write_byte_data(int file, __u8 command, __u8 value) {
+ union i2c_smbus_data data;
+ data.byte = value;
+ return i2c_smbus_access(file,I2C_SMBUS_WRITE,command, I2C_SMBUS_BYTE_DATA, &data);
+}
+// =========================================================================================================================
+
+int smbus_write_byte(uint8_t addr, uint8_t value) {
+ return i2c_smbus_write_byte_data(smbus_fd, addr, value);
+}
+
+uint8_t smbus_read_byte(uint8_t addr) {
+ return i2c_smbus_read_byte_data(smbus_fd, addr);
+}
+
+void printk(int severity, const char* format, ...) {
+ va_list args;
+ va_start(args, format);
+ vprintf(format, args);
+ va_end(args);
+}
+
+static int w83795_set_bank(uint8_t bank)
+{
+ return smbus_write_byte(W83795_REG_BANKSEL, bank);
+}
+
+static uint8_t w83795_read(uint16_t reg)
+{
+ int ret;
+
+ ret = w83795_set_bank(reg >> 8);
+ if (ret < 0) {
+ printk(BIOS_DEBUG, "read failed to set bank %x\n", reg >> 8);
+ return -1;
+ }
+
+ ret = smbus_read_byte(reg & 0xff);
+ return ret;
+}
+
+static uint8_t w83795_write(uint16_t reg, uint8_t value)
+{
+ int err;
+
+ err = w83795_set_bank(reg >> 8);
+ if (err < 0) {
+ printk(BIOS_DEBUG, "write failed to set bank %x\n", reg >> 8);
+ return -1;
+ }
+
+ err = smbus_write_byte(reg & 0xff, value);
+ return err;
+}
+
+/*
+ * Configure Digital Temperature Sensor
+ */
+static void w83795_dts_configure(uint8_t dts_src)
+{
+ uint8_t val;
+
+ /* DIS */
+ val = w83795_read(W83795_REG_DTSC) & ~0x1;
+ val |= dts_src & 0x1;
+ w83795_write(W83795_REG_DTSC, val);
+
+ /* TODO
+ * Determine if DTS interface needs to be reset
+ * (W83795_REG_DTSC bit 7) before operation.
+ */
+}
+
+static uint32_t w83795_set_fan_mode(w83795_fan_mode_t mode)
+{
+ if (mode == SPEED_CRUISE_MODE) {
+ w83795_write(W83795_REG_FCMS1, 0xFF);
+ printk(BIOS_INFO, "W83795G/ADG work in Speed Cruise Mode\n");
+ } else {
+ w83795_write(W83795_REG_FCMS1, 0x00);
+ if (mode == THERMAL_CRUISE_MODE) {
+ w83795_write(W83795_REG_FCMS2, 0x00);
+ printk(BIOS_INFO, "W83795G/ADG work in Thermal Cruise Mode\n");
+ } else if (mode == SMART_FAN_MODE) {
+ w83795_write(W83795_REG_FCMS2, 0x3F);
+ printk(BIOS_INFO, "W83795G/ADG work in Smart Fan Mode\n");
+ } else {
+ printk(BIOS_INFO, "W83795G/ADG work in Manual Mode\n");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static void w83795_set_fan(w83795_fan_mode_t mode)
+{
+ /* set fan output controlled mode (FCMS)*/
+ w83795_set_fan_mode(mode);
+
+ if (mode == SMART_FAN_MODE) {
+ /* Set the Relative Register-at SMART FAN IV Control Mode Table */
+ //SFIV TODO
+ }
+
+ /* Set Hysteresis of Temperature (HT) */
+ //TODO
+}
+
+static uint8_t fan_pct_to_cfg_val(uint8_t percent)
+{
+ uint16_t cfg = (((unsigned int)percent * 10000) / 3922);
+ if (cfg > 0xff)
+ cfg = 0xff;
+ return cfg;
+}
+
+static uint8_t millivolts_to_limit_value_type1(int millivolts)
+{
+ /* Datasheet v1.41 pages 44 and 70 (VSEN1 - VSEN11, VTT) */
+ return ((millivolts / 2) >> 2);
+}
+
+static uint8_t millivolts_to_limit_value_type2(int millivolts)
+{
+ /* Datasheet v1.41 page pages 44 and 70 (3VSB, 3VDD, VBAT) */
+ return ((millivolts / 6) >> 2);
+}
+
+static uint16_t millivolts_to_limit_value_type3(int millivolts)
+{
+ /* Datasheet v1.41 page 45 (VSEN12, VSEN13, VDSEN14 - VDSEN17) */
+ return (millivolts / 2);
+}
+
+void w83795_init(w83795_fan_mode_t mode, uint8_t dts_src, struct drivers_i2c_w83795_config *config)
+{
+ uint8_t i;
+ uint8_t val;
+ uint16_t limit_value;
+
+ if (smbus_read_byte(0x00) < 0) {
+ printk(BIOS_ERR, "W83795G/ADG Nuvoton H/W Monitor not found\n");
+ return;
+ }
+ val = w83795_read(W83795_REG_CONFIG);
+ if ((val & W83795_REG_CONFIG_CONFIG48) == 0)
+ printk(BIOS_INFO, "Found 64 pin W83795G Nuvoton H/W Monitor\n");
+ else
+ printk(BIOS_INFO, "Found 48 pin W83795ADG Nuvoton H/W Monitor\n");
+
+ /* Reset */
+ val |= W83795_REG_CONFIG_INIT;
+ w83795_write(W83795_REG_CONFIG, val);
+
+ /* Fan monitor settings */
+ w83795_write(W83795_REG_FANIN_CTRL1, config->fanin_ctl1);
+ w83795_write(W83795_REG_FANIN_CTRL2, config->fanin_ctl2);
+
+ /* Temperature thresholds */
+ w83795_write(W83795_REG_TEMP_CRIT(0), config->tr1_critical_temperature);
+ w83795_write(W83795_REG_TEMP_CRIT_HYSTER(0), config->tr1_critical_hysteresis);
+ w83795_write(W83795_REG_TEMP_WARN(0), config->tr1_warning_temperature);
+ w83795_write(W83795_REG_TEMP_WARN_HYSTER(0), config->tr1_warning_hysteresis);
+ w83795_write(W83795_REG_TEMP_CRIT(1), config->tr2_critical_temperature);
+ w83795_write(W83795_REG_TEMP_CRIT_HYSTER(1), config->tr2_critical_hysteresis);
+ w83795_write(W83795_REG_TEMP_WARN(1), config->tr2_warning_temperature);
+ w83795_write(W83795_REG_TEMP_WARN_HYSTER(1), config->tr2_warning_hysteresis);
+ w83795_write(W83795_REG_TEMP_CRIT(2), config->tr3_critical_temperature);
+ w83795_write(W83795_REG_TEMP_CRIT_HYSTER(2), config->tr3_critical_hysteresis);
+ w83795_write(W83795_REG_TEMP_WARN(2), config->tr3_warning_temperature);
+ w83795_write(W83795_REG_TEMP_WARN_HYSTER(2), config->tr3_warning_hysteresis);
+ w83795_write(W83795_REG_TEMP_CRIT(3), config->tr4_critical_temperature);
+ w83795_write(W83795_REG_TEMP_CRIT_HYSTER(3), config->tr4_critical_hysteresis);
+ w83795_write(W83795_REG_TEMP_WARN(3), config->tr4_warning_temperature);
+ w83795_write(W83795_REG_TEMP_WARN_HYSTER(3), config->tr4_warning_hysteresis);
+ w83795_write(W83795_REG_TEMP_CRIT(4), config->tr5_critical_temperature);
+ w83795_write(W83795_REG_TEMP_CRIT_HYSTER(4), config->tr5_critical_hysteresis);
+ w83795_write(W83795_REG_TEMP_WARN(4), config->tr5_warning_temperature);
+ w83795_write(W83795_REG_TEMP_WARN_HYSTER(4), config->tr5_warning_hysteresis);
+ w83795_write(W83795_REG_TEMP_CRIT(5), config->tr6_critical_temperature);
+ w83795_write(W83795_REG_TEMP_CRIT_HYSTER(5), config->tr6_critical_hysteresis);
+ w83795_write(W83795_REG_TEMP_WARN(5), config->tr6_warning_temperature);
+ w83795_write(W83795_REG_TEMP_WARN_HYSTER(5), config->tr6_warning_hysteresis);
+
+ /* DTS temperature thresholds */
+ w83795_write(W83795_REG_DTS_CRIT, config->dts_critical_temperature);
+ w83795_write(W83795_REG_DTS_CRIT_HYSTER, config->dts_critical_hysteresis);
+ w83795_write(W83795_REG_DTS_WARN, config->dts_warning_temperature);
+ w83795_write(W83795_REG_DTS_WARN_HYSTER, config->dts_warning_hysteresis);
+
+ /* Configure DTS registers in bank3 before enabling DTS */
+ w83795_dts_configure(dts_src);
+
+ /* DTS enable */
+ w83795_write(W83795_REG_DTSE, config->temp_dtse);
+
+ /* Temperature monitor settings */
+ w83795_write(W83795_REG_TEMP_CTRL1, config->temp_ctl1);
+ w83795_write(W83795_REG_TEMP_CTRL2, config->temp_ctl2);
+
+ /* Temperature to fan mappings */
+ w83795_write(W83795_REG_TFMR(0), config->temp1_fan_select);
+ w83795_write(W83795_REG_TFMR(1), config->temp2_fan_select);
+ w83795_write(W83795_REG_TFMR(2), config->temp3_fan_select);
+ w83795_write(W83795_REG_TFMR(3), config->temp4_fan_select);
+ w83795_write(W83795_REG_TFMR(4), config->temp5_fan_select);
+ w83795_write(W83795_REG_TFMR(5), config->temp6_fan_select);
+
+ /* Temperature data source to temperature mappings */
+ w83795_write(W83795_REG_T12TSS, ((config->temp2_source_select & 0x0f) << 4) | (config->temp1_source_select & 0x0f));
+ w83795_write(W83795_REG_T34TSS, ((config->temp4_source_select & 0x0f) << 4) | (config->temp3_source_select & 0x0f));
+ w83795_write(W83795_REG_T56TSS, ((config->temp6_source_select & 0x0f) << 4) | (config->temp5_source_select & 0x0f));
+
+ /* Set critical temperatures
+ * If any sensor exceeds the associated critical temperature,
+ * all fans will be forced to full speed.
+ */
+ w83795_write(W83795_REG_CTFS(0), config->temp1_critical_temperature);
+ w83795_write(W83795_REG_CTFS(1), config->temp2_critical_temperature);
+ w83795_write(W83795_REG_CTFS(2), config->temp3_critical_temperature);
+ w83795_write(W83795_REG_CTFS(3), config->temp4_critical_temperature);
+ w83795_write(W83795_REG_CTFS(4), config->temp5_critical_temperature);
+ w83795_write(W83795_REG_CTFS(5), config->temp6_critical_temperature);
+
+ /* Set fan control target temperatures */
+ w83795_write(W83795_REG_TTTI(0), config->temp1_target_temperature);
+ w83795_write(W83795_REG_TTTI(1), config->temp2_target_temperature);
+ w83795_write(W83795_REG_TTTI(2), config->temp3_target_temperature);
+ w83795_write(W83795_REG_TTTI(3), config->temp4_target_temperature);
+ w83795_write(W83795_REG_TTTI(4), config->temp5_target_temperature);
+ w83795_write(W83795_REG_TTTI(5), config->temp6_target_temperature);
+
+ /* Set fan stall prevention parameters */
+ w83795_write(W83795_REG_FAN_NONSTOP(0), config->fan1_nonstop);
+ w83795_write(W83795_REG_FAN_NONSTOP(1), config->fan2_nonstop);
+ w83795_write(W83795_REG_FAN_NONSTOP(2), config->fan3_nonstop);
+ w83795_write(W83795_REG_FAN_NONSTOP(3), config->fan4_nonstop);
+ w83795_write(W83795_REG_FAN_NONSTOP(4), config->fan5_nonstop);
+ w83795_write(W83795_REG_FAN_NONSTOP(5), config->fan6_nonstop);
+ w83795_write(W83795_REG_FAN_NONSTOP(6), config->fan7_nonstop);
+ w83795_write(W83795_REG_FAN_NONSTOP(7), config->fan8_nonstop);
+
+ /* Set fan default speed */
+ w83795_write(W83795_REG_DFSP, fan_pct_to_cfg_val(config->default_speed));
+
+ /* Set initial fan speeds */
+ w83795_write(W83795_REG_FAN_MANUAL_SPEED(0), fan_pct_to_cfg_val(config->fan1_duty));
+ w83795_write(W83795_REG_FAN_MANUAL_SPEED(1), fan_pct_to_cfg_val(config->fan2_duty));
+ w83795_write(W83795_REG_FAN_MANUAL_SPEED(2), fan_pct_to_cfg_val(config->fan3_duty));
+ w83795_write(W83795_REG_FAN_MANUAL_SPEED(3), fan_pct_to_cfg_val(config->fan4_duty));
+ w83795_write(W83795_REG_FAN_MANUAL_SPEED(4), fan_pct_to_cfg_val(config->fan5_duty));
+ w83795_write(W83795_REG_FAN_MANUAL_SPEED(5), fan_pct_to_cfg_val(config->fan6_duty));
+ w83795_write(W83795_REG_FAN_MANUAL_SPEED(6), fan_pct_to_cfg_val(config->fan7_duty));
+ w83795_write(W83795_REG_FAN_MANUAL_SPEED(7), fan_pct_to_cfg_val(config->fan8_duty));
+
+ /* Voltage monitor settings */
+ w83795_write(W83795_REG_VOLT_CTRL1, config->volt_ctl1);
+ w83795_write(W83795_REG_VOLT_CTRL2, config->volt_ctl2);
+
+ /* Voltage high/low limits */
+ w83795_write(W83795_REG_VOLT_LIM_HIGH(0), millivolts_to_limit_value_type1(config->vcore1_high_limit_mv));
+ w83795_write(W83795_REG_VOLT_LIM_LOW(0), millivolts_to_limit_value_type1(config->vcore1_low_limit_mv));
+ w83795_write(W83795_REG_VOLT_LIM_HIGH(1), millivolts_to_limit_value_type1(config->vcore2_high_limit_mv));
+ w83795_write(W83795_REG_VOLT_LIM_LOW(1), millivolts_to_limit_value_type1(config->vcore2_low_limit_mv));
+ w83795_write(W83795_REG_VOLT_LIM_HIGH(2), millivolts_to_limit_value_type1(config->vsen3_high_limit_mv));
+ w83795_write(W83795_REG_VOLT_LIM_LOW(2), millivolts_to_limit_value_type1(config->vsen3_low_limit_mv));
+ w83795_write(W83795_REG_VOLT_LIM_HIGH(3), millivolts_to_limit_value_type1(config->vsen4_high_limit_mv));
+ w83795_write(W83795_REG_VOLT_LIM_LOW(3), millivolts_to_limit_value_type1(config->vsen4_low_limit_mv));
+ w83795_write(W83795_REG_VOLT_LIM_HIGH(4), millivolts_to_limit_value_type1(config->vsen5_high_limit_mv));
+ w83795_write(W83795_REG_VOLT_LIM_LOW(4), millivolts_to_limit_value_type1(config->vsen5_low_limit_mv));
+ w83795_write(W83795_REG_VOLT_LIM_HIGH(5), millivolts_to_limit_value_type1(config->vsen6_high_limit_mv));
+ w83795_write(W83795_REG_VOLT_LIM_LOW(5), millivolts_to_limit_value_type1(config->vsen6_low_limit_mv));
+ w83795_write(W83795_REG_VOLT_LIM_HIGH(6), millivolts_to_limit_value_type1(config->vsen7_high_limit_mv));
+ w83795_write(W83795_REG_VOLT_LIM_LOW(6), millivolts_to_limit_value_type1(config->vsen7_low_limit_mv));
+ w83795_write(W83795_REG_VOLT_LIM_HIGH(7), millivolts_to_limit_value_type1(config->vsen8_high_limit_mv));
+ w83795_write(W83795_REG_VOLT_LIM_LOW(7), millivolts_to_limit_value_type1(config->vsen8_low_limit_mv));
+ w83795_write(W83795_REG_VOLT_LIM_HIGH(8), millivolts_to_limit_value_type1(config->vsen9_high_limit_mv));
+ w83795_write(W83795_REG_VOLT_LIM_LOW(8), millivolts_to_limit_value_type1(config->vsen9_low_limit_mv));
+ w83795_write(W83795_REG_VOLT_LIM_HIGH(9), millivolts_to_limit_value_type1(config->vsen10_high_limit_mv));
+ w83795_write(W83795_REG_VOLT_LIM_LOW(9), millivolts_to_limit_value_type1(config->vsen10_low_limit_mv));
+ w83795_write(W83795_REG_VOLT_LIM_HIGH(10), millivolts_to_limit_value_type1(config->vsen11_high_limit_mv));
+ w83795_write(W83795_REG_VOLT_LIM_LOW(10), millivolts_to_limit_value_type1(config->vsen11_low_limit_mv));
+ w83795_write(W83795_REG_VOLT_LIM_HIGH(11), millivolts_to_limit_value_type1(config->vtt_high_limit_mv));
+ w83795_write(W83795_REG_VOLT_LIM_LOW(11), millivolts_to_limit_value_type1(config->vtt_low_limit_mv));
+ w83795_write(W83795_REG_VOLT_LIM_HIGH(12), millivolts_to_limit_value_type2(config->vdd_high_limit_mv));
+ w83795_write(W83795_REG_VOLT_LIM_LOW(12), millivolts_to_limit_value_type2(config->vdd_low_limit_mv));
+ w83795_write(W83795_REG_VOLT_LIM_HIGH(13), millivolts_to_limit_value_type2(config->vsb_high_limit_mv));
+ w83795_write(W83795_REG_VOLT_LIM_LOW(13), millivolts_to_limit_value_type2(config->vsb_low_limit_mv));
+ w83795_write(W83795_REG_VOLT_LIM_HIGH(14), millivolts_to_limit_value_type2(config->vbat_high_limit_mv));
+ w83795_write(W83795_REG_VOLT_LIM_LOW(14), millivolts_to_limit_value_type2(config->vbat_low_limit_mv));
+
+ /* VSEN12 limits */
+ if (config->temp_ctl1 & 0x2) {
+ limit_value = millivolts_to_limit_value_type3(config->vsen12_high_limit_mv);
+ w83795_write(W83795_REG_VOLT_LIM_HIGH_2_M(4), limit_value >> 2);
+ w83795_write(W83795_REG_VOLT_LIM_HIGH_2_L(4), limit_value & 0x3);
+ limit_value = millivolts_to_limit_value_type3(config->vsen12_low_limit_mv);
+ w83795_write(W83795_REG_VOLT_LIM_LOW_2_M(4), limit_value >> 2);
+ w83795_write(W83795_REG_VOLT_LIM_LOW_2_L(4), limit_value & 0x3);
+ }
+
+ /* VSEN13 limits */
+ if (config->temp_ctl1 & 0x8) {
+ limit_value = millivolts_to_limit_value_type3(config->vsen13_high_limit_mv);
+ w83795_write(W83795_REG_VOLT_LIM_HIGH_2_M(5), limit_value >> 2);
+ w83795_write(W83795_REG_VOLT_LIM_HIGH_2_L(5), limit_value & 0x3);
+ limit_value = millivolts_to_limit_value_type3(config->vsen13_low_limit_mv);
+ w83795_write(W83795_REG_VOLT_LIM_LOW_2_M(5), limit_value >> 2);
+ w83795_write(W83795_REG_VOLT_LIM_LOW_2_L(5), limit_value & 0x3);
+ }
+
+ w83795_set_fan(mode);
+
+ /* Show current fan control settings */
+ printk(BIOS_INFO, "Fan\tCTFS(celsius)\tTTTI(celsius)\n");
+ for (i = 0; i < 6; i++) {
+ val = w83795_read(W83795_REG_CTFS(i));
+ printk(BIOS_INFO, " %x\t%d", i + 1, val);
+ val = w83795_read(W83795_REG_TTTI(i));
+ printk(BIOS_INFO, "\t%d\n", val);
+ }
+
+ /* Show current temperatures */
+ for (i = 0; i < 8; i++) {
+ val = w83795_read(W83795_REG_DTS(i));
+ printk(BIOS_DEBUG, "DTS%x current value: %x\n", i + 1, val);
+ }
+
+ /* Start monitoring / fan control */
+ val = w83795_read(W83795_REG_CONFIG);
+ val |= W83795_REG_CONFIG_START;
+ w83795_write(W83795_REG_CONFIG, val);
+}
diff --git a/common/recipes-core/fan-ctrl/fan-ctrl/w83795.h b/common/recipes-core/fan-ctrl/fan-ctrl/w83795.h
new file mode 100644
index 0000000..25046d2
--- /dev/null
+++ b/common/recipes-core/fan-ctrl/fan-ctrl/w83795.h
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2012 Advanced Micro Devices, Inc.
+ * Copyright (C) 2015-2017 Raptor Engineering
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _W83795_H_
+#define _W83795_H_
+
+#define W83795_REG_I2C_ADDR 0xFC
+#define W83795_REG_BANKSEL 0x00
+#define W83795_REG_CONFIG 0x01
+#define W83795_REG_CONFIG_START 0x01
+#define W83795_REG_CONFIG_CONFIG48 0x04
+#define W83795_REG_CONFIG_INIT 0x80
+
+#define W83795_REG_VOLT_CTRL1 0x02
+#define W83795_REG_VOLT_CTRL2 0x03
+#define W83795_REG_TEMP_CTRL1 0x04 /* Temperature Monitoring Control Register */
+#define W83795_REG_TEMP_CTRL2 0x05 /* Temperature Monitoring Control Register */
+#define W83795_REG_FANIN_CTRL1 0x06
+#define W83795_REG_FANIN_CTRL2 0x07
+#define W83795_REG_TEMP_CTRL1_EN_DTS 0x20 /* Enable DTS (Digital Temperature Sensor) interface from INTEL PECI or AMD SB-TSI. */
+#define DTS_SRC_INTEL_PECI (0 << 0)
+#define DTS_SRC_AMD_SBTSI (1 << 0)
+
+#define W83795_REG_TTTI(n) (0x260 + (n)) /* Target temperature W83795G/ADG will try to tune the fan output to keep */
+#define W83795_REG_CTFS(n) (0x268 + (n)) /* Critical Temperature to Full Speed all fan */
+#define W83795_REG_DTSC 0x301 /* Digital Temperature Sensor Configuration */
+
+#define W83795_REG_DTSE 0x302 /* Digital Temperature Sensor Enable */
+#define W83795_REG_DTS(n) (0x26 + (n))
+#define W83795_REG_VRLSB 0x3C
+
+#define W83795_REG_TEMP_TR1 0x21
+#define W83795_REG_TEMP_TR2 0x22
+#define W83795_REG_TEMP_TR3 0x23
+#define W83795_REG_TEMP_TR4 0x24
+#define W83795_REG_TEMP_TR5 0x1F
+#define W83795_REG_TEMP_TR6 0x20
+
+#define W83795_REG_VOLT_LIM_HIGH(n) (0x70 + (n * 2)) /* Voltage high limit (0 == VSEN1) */
+#define W83795_REG_VOLT_LIM_LOW(n) (0x71 + (n * 2)) /* Voltage low limit (0 == VSEN1) */
+#define W83795_REG_VOLT_LIM_HIGH_2_M(n) (0x96 + (n * 4)) /* Voltage high limit MSB (0 == VDSEN14) */
+#define W83795_REG_VOLT_LIM_LOW_2_M(n) (0x97 + (n * 4)) /* Voltage low limit MSB (0 == VDSEN14) */
+#define W83795_REG_VOLT_LIM_HIGH_2_L(n) (0x98 + (n * 4)) /* Voltage high limit LSB (0 == VDSEN14) */
+#define W83795_REG_VOLT_LIM_LOW_2_L(n) (0x99 + (n * 4)) /* Voltage low limit LSB (0 == VDSEN14) */
+
+#define W83795_REG_TEMP_CRIT(n) (0x96 + (n * 4)) /* Temperature critical limit */
+#define W83795_REG_TEMP_CRIT_HYSTER(n) (0x97 + (n * 4)) /* Temperature critical limit hysteresis */
+#define W83795_REG_TEMP_WARN(n) (0x98 + (n * 4)) /* Temperature warning limit */
+#define W83795_REG_TEMP_WARN_HYSTER(n) (0x99 + (n * 4)) /* Temperature warning limit hysteresis */
+
+#define W83795_REG_DTS_CRIT 0xB2 /* Temperature critical limit */
+#define W83795_REG_DTS_CRIT_HYSTER 0xB3 /* Temperature critical limit hysteresis */
+#define W83795_REG_DTS_WARN 0xB4 /* Temperature warning limit */
+#define W83795_REG_DTS_WARN_HYSTER 0xB5 /* Temperature warning limit hysteresis */
+
+#define W83795_REG_FCMS1 0x201
+#define W83795_REG_FCMS2 0x208
+#define W83795_REG_TFMR(n) (0x202 + (n)) /* Temperature to fan mapping */
+#define W83795_REG_T12TSS 0x209 /* Temperature Source Selection Register 1 */
+#define W83795_REG_T34TSS 0x20A /* Temperature Source Selection Register 2 */
+#define W83795_REG_T56TSS 0x20B /* Temperature Source Selection Register 3 */
+#define W83795_REG_FAN_MANUAL_SPEED(n) (0x210 + n)
+#define W83795_REG_DFSP 0x20C
+
+#define W83795_REG_FAN_NONSTOP(n) (0x228 + (n)) /* Fan Nonstop Value */
+
+#define W83795_REG_FTSH(n) (0x240 + (n) * 2)
+#define W83795_REG_FTSL(n) (0x241 + (n) * 2)
+#define W83795_REG_TFTS 0x250
+
+typedef enum w83795_fan_mode {
+ SPEED_CRUISE_MODE = 0, ///< Fan Speed Cruise mode keeps the fan speed in a specified range
+ THERMAL_CRUISE_MODE = 1, ///< Thermal Cruise mode is an algorithm to control the fan speed to keep the temperature source around the TTTI
+ SMART_FAN_MODE = 2, ///< Smart Fan mode offers 6 slopes to control the fan speed
+ MANUAL_MODE = 3, ///< control manually
+} w83795_fan_mode_t;
+
+struct drivers_i2c_w83795_config {
+ uint8_t fanin_ctl1;
+ uint8_t fanin_ctl2;
+
+ uint8_t temp_ctl1;
+ uint8_t temp_ctl2;
+ uint8_t temp_dtse;
+
+ uint8_t volt_ctl1;
+ uint8_t volt_ctl2;
+
+ uint8_t temp1_fan_select;
+ uint8_t temp2_fan_select;
+ uint8_t temp3_fan_select;
+ uint8_t temp4_fan_select;
+ uint8_t temp5_fan_select;
+ uint8_t temp6_fan_select;
+
+ uint8_t temp1_source_select;
+ uint8_t temp2_source_select;
+ uint8_t temp3_source_select;
+ uint8_t temp4_source_select;
+ uint8_t temp5_source_select;
+ uint8_t temp6_source_select;
+
+ uint32_t vcore1_high_limit_mv; /* mV */
+ uint32_t vcore1_low_limit_mv; /* mV */
+ uint32_t vcore2_high_limit_mv; /* mV */
+ uint32_t vcore2_low_limit_mv; /* mV */
+ uint32_t vtt_high_limit_mv; /* mV */
+ uint32_t vtt_low_limit_mv; /* mV */
+ uint32_t vsen3_high_limit_mv; /* mV */
+ uint32_t vsen3_low_limit_mv; /* mV */
+ uint32_t vsen4_high_limit_mv; /* mV */
+ uint32_t vsen4_low_limit_mv; /* mV */
+ uint32_t vsen5_high_limit_mv; /* mV */
+ uint32_t vsen5_low_limit_mv; /* mV */
+ uint32_t vsen6_high_limit_mv; /* mV */
+ uint32_t vsen6_low_limit_mv; /* mV */
+ uint32_t vsen7_high_limit_mv; /* mV */
+ uint32_t vsen7_low_limit_mv; /* mV */
+ uint32_t vsen8_high_limit_mv; /* mV */
+ uint32_t vsen8_low_limit_mv; /* mV */
+ uint32_t vsen9_high_limit_mv; /* mV */
+ uint32_t vsen9_low_limit_mv; /* mV */
+ uint32_t vsen10_high_limit_mv; /* mV */
+ uint32_t vsen10_low_limit_mv; /* mV */
+ uint32_t vsen11_high_limit_mv; /* mV */
+ uint32_t vsen11_low_limit_mv; /* mV */
+ uint32_t vsen12_high_limit_mv; /* mV */
+ uint32_t vsen12_low_limit_mv; /* mV */
+ uint32_t vsen13_high_limit_mv; /* mV */
+ uint32_t vsen13_low_limit_mv; /* mV */
+ uint32_t vdd_high_limit_mv; /* mV */
+ uint32_t vdd_low_limit_mv; /* mV */
+ uint32_t vsb_high_limit_mv; /* mV */
+ uint32_t vsb_low_limit_mv; /* mV */
+ uint32_t vbat_high_limit_mv; /* mV */
+ uint32_t vbat_low_limit_mv; /* mV */
+
+ int8_t tr1_critical_temperature; /* °C */
+ int8_t tr1_critical_hysteresis; /* °C */
+ int8_t tr1_warning_temperature; /* °C */
+ int8_t tr1_warning_hysteresis; /* °C */
+ int8_t tr2_critical_temperature; /* °C */
+ int8_t tr2_critical_hysteresis; /* °C */
+ int8_t tr2_warning_temperature; /* °C */
+ int8_t tr2_warning_hysteresis; /* °C */
+ int8_t tr3_critical_temperature; /* °C */
+ int8_t tr3_critical_hysteresis; /* °C */
+ int8_t tr3_warning_temperature; /* °C */
+ int8_t tr3_warning_hysteresis; /* °C */
+ int8_t tr4_critical_temperature; /* °C */
+ int8_t tr4_critical_hysteresis; /* °C */
+ int8_t tr4_warning_temperature; /* °C */
+ int8_t tr4_warning_hysteresis; /* °C */
+ int8_t tr5_critical_temperature; /* °C */
+ int8_t tr5_critical_hysteresis; /* °C */
+ int8_t tr5_warning_temperature; /* °C */
+ int8_t tr5_warning_hysteresis; /* °C */
+ int8_t tr6_critical_temperature; /* °C */
+ int8_t tr6_critical_hysteresis; /* °C */
+ int8_t tr6_warning_temperature; /* °C */
+ int8_t tr6_warning_hysteresis; /* °C */
+ int8_t dts_critical_temperature; /* °C */
+ int8_t dts_critical_hysteresis; /* °C */
+ int8_t dts_warning_temperature; /* °C */
+ int8_t dts_warning_hysteresis; /* °C */
+
+ int8_t temp1_critical_temperature; /* °C */
+ int8_t temp2_critical_temperature; /* °C */
+ int8_t temp3_critical_temperature; /* °C */
+ int8_t temp4_critical_temperature; /* °C */
+ int8_t temp5_critical_temperature; /* °C */
+ int8_t temp6_critical_temperature; /* °C */
+
+ int8_t temp1_target_temperature; /* °C */
+ int8_t temp2_target_temperature; /* °C */
+ int8_t temp3_target_temperature; /* °C */
+ int8_t temp4_target_temperature; /* °C */
+ int8_t temp5_target_temperature; /* °C */
+ int8_t temp6_target_temperature; /* °C */
+
+ uint8_t fan1_nonstop; /* % of full speed (0-100) */
+ uint8_t fan2_nonstop; /* % of full speed (0-100) */
+ uint8_t fan3_nonstop; /* % of full speed (0-100) */
+ uint8_t fan4_nonstop; /* % of full speed (0-100) */
+ uint8_t fan5_nonstop; /* % of full speed (0-100) */
+ uint8_t fan6_nonstop; /* % of full speed (0-100) */
+ uint8_t fan7_nonstop; /* % of full speed (0-100) */
+ uint8_t fan8_nonstop; /* % of full speed (0-100) */
+
+ uint8_t default_speed; /* % of full speed (0-100) */
+
+ uint8_t fan1_duty; /* % of full speed (0-100) */
+ uint8_t fan2_duty; /* % of full speed (0-100) */
+ uint8_t fan3_duty; /* % of full speed (0-100) */
+ uint8_t fan4_duty; /* % of full speed (0-100) */
+ uint8_t fan5_duty; /* % of full speed (0-100) */
+ uint8_t fan6_duty; /* % of full speed (0-100) */
+ uint8_t fan7_duty; /* % of full speed (0-100) */
+ uint8_t fan8_duty; /* % of full speed (0-100) */
+
+ uint8_t smbus_aux; /* 0 == device located on primary SMBUS,
+ * 1 == device located on first auxiliary
+ * SMBUS channel,
+ * <n> == device located on <n> auxiliary
+ * SMBUS channel
+ */
+};
+
+void w83795_init(w83795_fan_mode_t mode, uint8_t dts_src, struct drivers_i2c_w83795_config *config);
+
+#endif
+
diff --git a/common/recipes-core/fan-ctrl/fan-ctrl/watchdog.cpp b/common/recipes-core/fan-ctrl/fan-ctrl/watchdog.cpp
index f6e5a45..b2a7a88 100644
--- a/common/recipes-core/fan-ctrl/fan-ctrl/watchdog.cpp
+++ b/common/recipes-core/fan-ctrl/fan-ctrl/watchdog.cpp
@@ -1,6 +1,7 @@
/*
* watchdog
*
+ * Copyright 2017 Raptor Engineering, LLC
* Copyright 2014-present Facebook. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -25,6 +26,11 @@
#include <pthread.h>
#include <syslog.h>
#include <unistd.h>
+#include <time.h>
+#include <sys/ioctl.h>
+#include <linux/watchdog.h>
+
+// #define DEBUG_WATCHDOG 1
#define WATCHDOG_START_KEY "x"
#define WATCHDOG_STOP_KEY "X"
@@ -32,6 +38,10 @@
#define WATCHDOG_PERSISTENT_KEY "V"
#define WATCHDOG_NON_PERSISTENT_KEY "a"
+#ifdef DEBUG_WATCHDOG
+static time_t watchdog_last_kick = 0;
+#endif
+
static int watchdog_dev = -1;
/* This is needed to prevent rapid consecutive stop/start watchdog calls from
@@ -104,7 +114,7 @@ int start_watchdog(const int auto_mode) {
return 0;
}
- while (((watchdog_dev = open("/dev/watchdog", O_WRONLY)) == -1) &&
+ while (((watchdog_dev = open("/dev/watchdog", O_RDWR)) == -1) &&
errno == EINTR);
/* Fail if watchdog device is invalid or if the user asked for auto
@@ -118,6 +128,9 @@ int start_watchdog(const int auto_mode) {
while ((status = write(watchdog_dev, WATCHDOG_START_KEY, 1)) == 0
&& errno == EINTR);
pthread_mutex_unlock(&watchdog_lock);
+#ifdef DEBUG_WATCHDOG
+ watchdog_last_kick = time(NULL);
+#endif
syslog(LOG_INFO, "system watchdog started.\n");
return 1;
@@ -162,6 +175,16 @@ void set_persistent_watchdog(enum watchdog_persistent_en persistent) {
static int kick_watchdog_unsafe() {
int status = 0;
+#ifdef DEBUG_WATCHDOG
+ int timeout = -1;
+ if (ioctl(watchdog_dev, WDIOC_GETTIMEOUT, &timeout) < 0) {
+ syslog(LOG_DEBUG, "Watchdog: WDIOC_GETTIMEOUT ioctl failed with errno %d\n", errno);
+ }
+ else {
+ syslog(LOG_DEBUG, "Watchdog: timeout set to %d seconds (last kick was %d seconds ago)\n", timeout, time(NULL) - watchdog_last_kick);
+ }
+ watchdog_last_kick = time(NULL);
+#endif
if (watchdog_dev != -1) {
while ((status = write(watchdog_dev, watchdog_kick_key, 1)) == 0
&& errno == EINTR);
diff --git a/common/recipes-core/fan-ctrl/fan-ctrl_0.1.bb b/common/recipes-core/fan-ctrl/fan-ctrl_0.1.bb
index 1abfaaa..74c388c 100644
--- a/common/recipes-core/fan-ctrl/fan-ctrl_0.1.bb
+++ b/common/recipes-core/fan-ctrl/fan-ctrl_0.1.bb
@@ -19,18 +19,22 @@ DESCRIPTION = "The utilities to control fan."
SECTION = "base"
PR = "r1"
LICENSE = "GPLv2"
-LIC_FILES_CHKSUM = "file://fand.cpp;beginline=6;endline=18;md5=da35978751a9d71b73679307c4d296ec"
+LIC_FILES_CHKSUM = "file://fand.cpp;beginline=7;endline=19;md5=da35978751a9d71b73679307c4d296ec"
SRC_URI = "file://README \
file://Makefile \
file://fand.cpp \
file://watchdog.h \
file://watchdog.cpp \
+ file://w83795.h \
+ file://w83795.cpp \
+ file://platform_sensor_init.cpp \
"
S = "${WORKDIR}"
binfiles = "fand \
+ platform_sensor_init \
"
otherfiles = "README"
diff --git a/common/recipes-utils/openbmc-gpio/files/ast2050_gpio_table.py b/common/recipes-utils/openbmc-gpio/files/ast2050_gpio_table.py
new file mode 100644
index 0000000..d49dc0b
--- /dev/null
+++ b/common/recipes-utils/openbmc-gpio/files/ast2050_gpio_table.py
@@ -0,0 +1,220 @@
+# Copyright 2017 Raptor Engineering, LLC
+# Copyright 2015-present Facebook. All rights reserved.
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+from __future__ import unicode_literals
+
+from openbmc_gpio_table import (
+ BitsEqual, BitsNotEqual, And, Or, Function)
+
+
+# The fallowing table is generated using:
+# python ast_gpio_parser.py data/ast2050-gpio.csv
+# DO NOT MODIFY THE TABLE!!!
+# Manual modification will be overridden!!!
+
+soc_gpio_table = {
+ 'A10': [
+ Function('VBCK', BitsEqual(0x70, [5], 0x1)),
+ Function('GPIOB5', None)
+ ],
+ 'A11': [
+ Function('FLBUSY#', BitsEqual(0x74, [2], 0x1)),
+ Function('GPIOB1', None)
+ ],
+ 'A12': [
+ Function('SDA7', BitsEqual(0x74, [14], 0x1)),
+ Function('GPIOH2', None)
+ ],
+ 'A13': [
+ Function('MII2DIO', BitsEqual(0x74, [20], 0x1)),
+ Function('SDA5', BitsEqual(0x74, [12], 0x1)),
+ Function('GPIOC6', None)
+ ],
+ 'A8': [
+ Function('PWM4', BitsEqual(0x74, [11], 0x1)),
+ Function('GPIOC5', None)
+ ],
+ 'A9': [
+ Function('PECIO', BitsEqual(0x74, [7], 0x1)),
+ Function('GPIOC1', None)
+ ],
+ 'B1': [
+ Function('OSCCLK', BitsEqual(0x2c, [1], 0x1)),
+ Function('DDCACLK', BitsEqual(0x74, [18], 0x1)),
+ Function('GPIOD7', None)
+ ],
+ 'B10': [
+ Function('VBCS', BitsEqual(0x70, [5], 0x1)),
+ Function('LRST#', BitsEqual(0x70, [23], 0x1)),
+ Function('GPIOB4', None)
+ ],
+ 'B11': [
+ Function('INTA#', BitsEqual(0x78, [4], 0x0)),
+ Function('GPIOB0', None)
+ ],
+ 'B12': [
+ Function('SCL7', BitsEqual(0x74, [14], 0x1)),
+ Function('GPIOH3', None)
+ ],
+ 'B13': [
+ Function('MII2DC', BitsEqual(0x74, [20], 0x1)),
+ Function('SCL5', BitsEqual(0x74, [12], 0x1)),
+ Function('GPIOC7', None)
+ ],
+ 'B2': [
+ Function('DDCADAT', BitsEqual(0x74, [18], 0x1)),
+ Function('GPIOD6', None)
+ ],
+ 'B8': [
+ Function('PWM3', BitsEqual(0x74, [10], 0x1)),
+ Function('GPIOC4', None)
+ ],
+ 'B9': [
+ Function('PECII', BitsEqual(0x74, [7], 0x1)),
+ Function('GPIOC0', None)
+ ],
+ 'C11': [
+ Function('PHYPD#', BitsEqual(0x74, [25], 0x1)),
+ Function('GPIOA5', None)
+ ],
+ 'C12': [
+ Function('SDA6', BitsEqual(0x74, [13], 0x1)),
+ Function('GPIOH0', None)
+ ],
+ 'C8': [
+ Function('PWM2', BitsEqual(0x74, [9], 0x1)),
+ Function('GPIOC3', None)
+ ],
+ 'C9': [
+ Function('VBDI', BitsEqual(0x70, [5], 0x1)),
+ Function('GPIOB7', None)
+ ],
+ 'D10': [
+ Function('FLWP#', BitsEqual(0x74, [2], 0x1)),
+ Function('GPIOB2', None)
+ ],
+ 'D11': [
+ Function('PHYLINK', BitsEqual(0x74, [25], 0x1)),
+ Function('GPIOA4', None)
+ ],
+ 'D12': [
+ Function('SCL6', BitsEqual(0x74, [13], 0x1)),
+ Function('GPIOH1', None)
+ ],
+ 'D8': [
+ Function('PWM1', BitsEqual(0x74, [8], 0x1)),
+ Function('GPIOC2', None)
+ ],
+ 'D9': [
+ Function('VBDO', BitsEqual(0x70, [5], 0x1)),
+ Function('WDTRST', BitsEqual(0x78, [3], 0x1)),
+ Function('GPIOB6', None)
+ ],
+ 'R1': [
+ Function('VP2', BitsEqual(0x74, [22], 0x1)),
+ Function('GPIOE2', None)
+ ],
+ 'R2': [
+ Function('VP1', BitsEqual(0x74, [22], 0x1)),
+ Function('GPIOE1', None)
+ ],
+ 'R3': [
+ Function('VP0', BitsEqual(0x74, [22], 0x1)),
+ Function('GPIOE0', None)
+ ],
+ 'R4': [
+ Function('VSYNC', BitsEqual(0x74, [15], 0x1)),
+ Function('VPAVSYNC', BitsEqual(0x74, [16], 0x1)),
+ Function('GPIOH5', None)
+ ],
+ 'T1': [
+ Function('VPACLK', BitsEqual(0x74, [16], 0x1)),
+ Function('GPIOH7', None)
+ ],
+ 'T2': [
+ Function('VP5', BitsEqual(0x74, [22], 0x1)),
+ Function('GPIOE5', None)
+ ],
+ 'T3': [
+ Function('VP4', BitsEqual(0x74, [22], 0x1)),
+ Function('GPIOE4', None)
+ ],
+ 'T4': [
+ Function('VP3', BitsEqual(0x74, [22], 0x1)),
+ Function('GPIOE3', None)
+ ],
+ 'U1': [
+ Function('VPADE', BitsEqual(0x74, [16], 0x1)),
+ Function('GPIOH6', None)
+ ],
+ 'U2': [
+ Function('HSYNC', BitsEqual(0x74, [15], 0x1)),
+ Function('VPAHSYNC', BitsEqual(0x74, [16], 0x1)),
+ Function('GPIOH4', None)
+ ],
+ 'U3': [
+ Function('VP7', BitsEqual(0x74, [22], 0x1)),
+ Function('GPIOE7', None)
+ ],
+ 'U4': [
+ Function('VP6', BitsEqual(0x74, [22], 0x1)),
+ Function('GPIOE6', None)
+ ],
+ 'V1': [
+ Function('VP11', BitsEqual(0x74, [22], 0x1)),
+ Function('GPIOF3', None)
+ ],
+ 'V2': [
+ Function('VP10', BitsEqual(0x74, [22], 0x1)),
+ Function('GPIOF2', None)
+ ],
+ 'V3': [
+ Function('VP9', BitsEqual(0x74, [22], 0x1)),
+ Function('GPIOF1', None)
+ ],
+ 'V4': [
+ Function('VP8', BitsEqual(0x74, [22], 0x1)),
+ Function('GPIOF0', None)
+ ],
+ 'W1': [
+ Function('VP15', BitsEqual(0x74, [23], 0x1)),
+ Function('GPIOF7', None)
+ ],
+ 'W2': [
+ Function('VP14', BitsEqual(0x74, [23], 0x1)),
+ Function('GPIOF6', None)
+ ],
+ 'W3': [
+ Function('VP13', BitsEqual(0x74, [23], 0x1)),
+ Function('GPIOF5', None)
+ ],
+ 'W4': [
+ Function('VP12', BitsEqual(0x74, [23], 0x1)),
+ Function('GPIOF4', None)
+ ],
+ 'Y3': [
+ Function('VP17', BitsEqual(0x74, [23], 0x1)),
+ Function('GPIOG1', None)
+ ],
+ 'Y4': [
+ Function('VP16', BitsEqual(0x74, [23], 0x1)),
+ Function('GPIOG0', None)
+ ],
+}
diff --git a/common/recipes-utils/openbmc-gpio/openbmc-gpio_0.1.bb b/common/recipes-utils/openbmc-gpio/openbmc-gpio_0.1.bb
index a2b46d4..bd64228 100644
--- a/common/recipes-utils/openbmc-gpio/openbmc-gpio_0.1.bb
+++ b/common/recipes-utils/openbmc-gpio/openbmc-gpio_0.1.bb
@@ -23,6 +23,7 @@ LIC_FILES_CHKSUM = "file://COPYING;md5=eb723b61539feef013de476e68b5c50a"
SRC_URI = " \
file://COPYING \
file://board_gpio_table.py \
+ file://ast2050_gpio_table.py \
file://openbmc_gpio.py \
file://openbmc_gpio_table.py \
file://openbmc_gpio_util.py \
@@ -49,7 +50,9 @@ RDEPENDS_${PN} = "python-core python-argparse python-subprocess"
do_board_defined_soc_table() {
if [ "${OPENBMC_GPIO_SOC_TABLE}" != "soc_gpio_table.py" ]; then
- mv -f "${S}/${OPENBMC_GPIO_SOC_TABLE}" "${S}/soc_gpio_table.py"
+ if [ "${OPENBMC_GPIO_SOC_TABLE}" != "ast2050_gpio_table.py" ]; then
+ mv -f "${S}/${OPENBMC_GPIO_SOC_TABLE}" "${S}/soc_gpio_table.py"
+ fi
fi
}
addtask board_defined_soc_table after do_unpack before do_build
OpenPOWER on IntegriCloud