mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-12-27 18:25:05 +00:00
Samus: Handle fan startup in the EC, not the fan controller
The fans on samus have a recommended minimum duty cycle of 20% while running, but 30% in order to start. We've been using the EC's built-in fan controller for the start requirement, but it has a minimum fast-start duty cycle of 50%. It turns out that that speed is noticeably noisy. This change handles the startup with logic in the EC instead, so that the fan only tries to spin at 30% initially (or if it drops too much below the minimum turning speed). BUG=chrome-os-partner:33429 BRANCH=ToT,samus TEST=make buildall -j Boot the system, let it idle with the browser windows closed, the browse a bit, then idle. Listen for changes to the fans. Before, I could hear the fans kick in and out as the AP load changed. Now it's much quieter. Change-Id: Id35215520c064eb6843686ec8bb5f3618dac6cf6 Signed-off-by: Bill Richardson <wfrichar@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/227658 Reviewed-by: Randall Spangler <rspangler@chromium.org>
This commit is contained in:
committed by
chrome-internal-fetch
parent
f0809a2399
commit
41cde66516
@@ -69,6 +69,7 @@ BUILD_ASSERT(ARRAY_SIZE(adc_channels) == ADC_CH_COUNT);
|
||||
const struct fan_t fans[] = {
|
||||
{.flags = FAN_USE_RPM_MODE,
|
||||
.rpm_min = 1000,
|
||||
.rpm_start = 1000,
|
||||
.rpm_max = 5050,
|
||||
.ch = 2,
|
||||
.pgood_gpio = GPIO_PP5000_PGOOD,
|
||||
|
||||
@@ -74,6 +74,7 @@ BUILD_ASSERT(ARRAY_SIZE(adc_channels) == ADC_CH_COUNT);
|
||||
const struct fan_t fans[] = {
|
||||
{.flags = FAN_USE_RPM_MODE,
|
||||
.rpm_min = 1000,
|
||||
.rpm_start = 1000,
|
||||
.rpm_max = 5050,
|
||||
.ch = 2,
|
||||
.pgood_gpio = GPIO_PP5000_PGOOD,
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
const struct fan_t fans[] = {
|
||||
{.flags = FAN_USE_RPM_MODE,
|
||||
.rpm_min = 1000,
|
||||
.rpm_start = 1500,
|
||||
.rpm_max = 5000,
|
||||
.ch = 0,
|
||||
.pgood_gpio = -1,
|
||||
@@ -49,7 +50,7 @@ int fan_get_rpm_mode(int ch)
|
||||
return mock_rpm_mode;
|
||||
}
|
||||
|
||||
static int mock_rpm;
|
||||
int mock_rpm;
|
||||
void fan_set_rpm_target(int ch, int rpm)
|
||||
{
|
||||
mock_rpm = rpm;
|
||||
|
||||
@@ -77,6 +77,7 @@ BUILD_ASSERT(ARRAY_SIZE(pwm_channels) == PWM_CH_COUNT);
|
||||
const struct fan_t fans[] = {
|
||||
{.flags = FAN_USE_RPM_MODE,
|
||||
.rpm_min = 1500,
|
||||
.rpm_start = 1500,
|
||||
.rpm_max = 9300,
|
||||
.ch = 0,
|
||||
.pgood_gpio = GPIO_PGOOD_5VALW,
|
||||
|
||||
@@ -30,6 +30,7 @@ BUILD_ASSERT(ARRAY_SIZE(adc_channels) == ADC_CH_COUNT);
|
||||
const struct fan_t fans[] = {
|
||||
{.flags = FAN_USE_RPM_MODE,
|
||||
.rpm_min = 1500,
|
||||
.rpm_start = 1500,
|
||||
.rpm_max = 8000,
|
||||
.ch = 0,
|
||||
.pgood_gpio = -1,
|
||||
|
||||
@@ -69,6 +69,7 @@ BUILD_ASSERT(ARRAY_SIZE(adc_channels) == ADC_CH_COUNT);
|
||||
const struct fan_t fans[] = {
|
||||
{.flags = FAN_USE_RPM_MODE,
|
||||
.rpm_min = 1000,
|
||||
.rpm_start = 1000,
|
||||
.rpm_max = 5050,
|
||||
.ch = 2,
|
||||
.pgood_gpio = GPIO_PP5000_PGOOD,
|
||||
|
||||
@@ -106,15 +106,17 @@ BUILD_ASSERT(ARRAY_SIZE(pwm_channels) == PWM_CH_COUNT);
|
||||
|
||||
/* Physical fans. These are logically separate from pwm_channels. */
|
||||
const struct fan_t fans[] = {
|
||||
{.flags = FAN_USE_RPM_MODE | FAN_USE_FAST_START,
|
||||
{.flags = FAN_USE_RPM_MODE,
|
||||
.rpm_min = 2286,
|
||||
.rpm_start = 3090,
|
||||
.rpm_max = 6350,
|
||||
.ch = 2,
|
||||
.pgood_gpio = -1,
|
||||
.enable_gpio = -1,
|
||||
},
|
||||
{.flags = FAN_USE_RPM_MODE | FAN_USE_FAST_START,
|
||||
{.flags = FAN_USE_RPM_MODE,
|
||||
.rpm_min = 2286,
|
||||
.rpm_start = 3090,
|
||||
.rpm_max = 6350,
|
||||
.ch = 3,
|
||||
.pgood_gpio = -1,
|
||||
|
||||
@@ -98,7 +98,7 @@ int fan_get_rpm_target(int ch)
|
||||
return (LM4_FAN_FANCMD(ch) & MAX_RPM) * RPM_SCALE;
|
||||
}
|
||||
|
||||
void fan_set_rpm_target(int ch, int rpm)
|
||||
test_mockable void fan_set_rpm_target(int ch, int rpm)
|
||||
{
|
||||
/* Apply fan scaling */
|
||||
if (rpm > 0)
|
||||
|
||||
25
common/fan.c
25
common/fan.c
@@ -15,6 +15,10 @@
|
||||
#include "system.h"
|
||||
#include "util.h"
|
||||
|
||||
/* Console output macros */
|
||||
#define CPUTS(outstr) cputs(CC_THERMAL, outstr)
|
||||
#define CPRINTS(format, args...) cprints(CC_THERMAL, format, ## args)
|
||||
|
||||
/* True if we're listening to the thermal control task. False if we're setting
|
||||
* things manually. */
|
||||
static int thermal_control_enabled[CONFIG_FANS];
|
||||
@@ -44,14 +48,29 @@ int fan_percent_to_rpm(int fan, int pct)
|
||||
/* The thermal task will only call this function with pct in [0,100]. */
|
||||
test_mockable void fan_set_percent_needed(int fan, int pct)
|
||||
{
|
||||
int rpm;
|
||||
int actual_rpm, new_rpm;
|
||||
static int prev_rpm[CONFIG_FANS];
|
||||
|
||||
if (!thermal_control_enabled[fan])
|
||||
return;
|
||||
|
||||
rpm = fan_percent_to_rpm(fan, pct);
|
||||
new_rpm = fan_percent_to_rpm(fan, pct);
|
||||
actual_rpm = fan_get_rpm_actual(fans[fan].ch);
|
||||
|
||||
fan_set_rpm_target(fans[fan].ch, rpm);
|
||||
/* If we want to turn and the fans are currently significantly below
|
||||
* the minimum turning speed, we should turn at least as fast as the
|
||||
* necessary start speed instead. */
|
||||
if (new_rpm &&
|
||||
actual_rpm < fans[fan].rpm_min * 9 / 10 &&
|
||||
new_rpm < fans[fan].rpm_start)
|
||||
new_rpm = fans[fan].rpm_start;
|
||||
|
||||
if (new_rpm != prev_rpm[fan]) {
|
||||
CPRINTS("Fan %d %d%% => %d rpm", fan, pct, new_rpm);
|
||||
prev_rpm[fan] = new_rpm;
|
||||
}
|
||||
|
||||
fan_set_rpm_target(fans[fan].ch, new_rpm);
|
||||
}
|
||||
|
||||
static void set_enabled(int fan, int enable)
|
||||
|
||||
@@ -11,7 +11,9 @@
|
||||
/* Characteristic of each physical fan */
|
||||
struct fan_t {
|
||||
unsigned int flags;
|
||||
/* rpm_min is to keep turning. rpm_start is to begin turning */
|
||||
int rpm_min;
|
||||
int rpm_start;
|
||||
int rpm_max;
|
||||
/* Hardware channel number (the meaning is chip-specific) */
|
||||
int ch;
|
||||
|
||||
@@ -31,7 +31,7 @@ test-list-host+=thermal flash queue kb_8042 extpwr_gpio console_edit system
|
||||
test-list-host+=sbs_charging adapter host_command thermal_falco led_spring
|
||||
test-list-host+=bklight_lid bklight_passthru interrupt timer_dos button
|
||||
test-list-host+=motion_lid math_util sbs_charging_v2 battery_get_params_smart
|
||||
test-list-host+=lightbar inductive_charging usb_pd
|
||||
test-list-host+=lightbar inductive_charging usb_pd fan
|
||||
|
||||
adapter-y=adapter.o
|
||||
battery_get_params_smart-y=battery_get_params_smart.o
|
||||
@@ -70,3 +70,4 @@ usb_pd-y=usb_pd.o
|
||||
utils-y=utils.o
|
||||
battery_get_params_smart-y=battery_get_params_smart.o
|
||||
lightbar-y=lightbar.o
|
||||
fan-y=fan.o
|
||||
|
||||
108
test/fan.c
Normal file
108
test/fan.c
Normal file
@@ -0,0 +1,108 @@
|
||||
/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*
|
||||
* Test thermal engine.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "console.h"
|
||||
#include "fan.h"
|
||||
#include "hooks.h"
|
||||
#include "host_command.h"
|
||||
#include "printf.h"
|
||||
#include "temp_sensor.h"
|
||||
#include "test_util.h"
|
||||
#include "thermal.h"
|
||||
#include "timer.h"
|
||||
#include "util.h"
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Tests */
|
||||
|
||||
static int test_fan(void)
|
||||
{
|
||||
/* "actual" fan speed from board/host/fan.c */
|
||||
extern int mock_rpm;
|
||||
|
||||
sleep(2);
|
||||
|
||||
/* With nothing else to do, fans default to full-on */
|
||||
TEST_ASSERT(fan_get_rpm_actual(0) == fans[0].rpm_max);
|
||||
|
||||
/*
|
||||
* fan_set_percent_needed() is normally called once a second by the
|
||||
* thermal task, but we're not using a thermal test in this test so
|
||||
* we can dink around with the fans without having to wait. The host
|
||||
* implementation just sets mock_rpm to whatever it's asked for.
|
||||
*/
|
||||
|
||||
/* Off */
|
||||
fan_set_percent_needed(0, 0);
|
||||
TEST_ASSERT(fan_get_rpm_actual(0) == 0);
|
||||
fan_set_percent_needed(0, 0);
|
||||
TEST_ASSERT(fan_get_rpm_actual(0) == 0);
|
||||
|
||||
/* On, but just barely */
|
||||
fan_set_percent_needed(0, 1);
|
||||
TEST_ASSERT(fan_get_rpm_actual(0) == fans[0].rpm_start);
|
||||
/* fan is above min speed now, so should be set to min */
|
||||
fan_set_percent_needed(0, 1);
|
||||
TEST_ASSERT(fan_get_rpm_actual(0) == fans[0].rpm_min);
|
||||
|
||||
/* Full speed */
|
||||
fan_set_percent_needed(0, 100);
|
||||
TEST_ASSERT(fan_get_rpm_actual(0) == fans[0].rpm_max);
|
||||
fan_set_percent_needed(0, 100);
|
||||
TEST_ASSERT(fan_get_rpm_actual(0) == fans[0].rpm_max);
|
||||
|
||||
/* Slow again */
|
||||
fan_set_percent_needed(0, 1);
|
||||
TEST_ASSERT(fan_get_rpm_actual(0) == fans[0].rpm_min);
|
||||
fan_set_percent_needed(0, 1);
|
||||
TEST_ASSERT(fan_get_rpm_actual(0) == fans[0].rpm_min);
|
||||
|
||||
/* Off */
|
||||
fan_set_percent_needed(0, 0);
|
||||
TEST_ASSERT(fan_get_rpm_actual(0) == 0);
|
||||
fan_set_percent_needed(0, 0);
|
||||
TEST_ASSERT(fan_get_rpm_actual(0) == 0);
|
||||
|
||||
/* On, but just barely */
|
||||
fan_set_percent_needed(0, 1);
|
||||
TEST_ASSERT(fan_get_rpm_actual(0) == fans[0].rpm_start);
|
||||
/* Force the mock_rpm to be slow, to simulate dragging */
|
||||
mock_rpm = fans[0].rpm_min - 105;
|
||||
/* It should keep trying for the start speed */
|
||||
fan_set_percent_needed(0, 1);
|
||||
TEST_ASSERT(fan_get_rpm_actual(0) == fans[0].rpm_start);
|
||||
/* But we have to keep forcing the mock_rpm back down */
|
||||
mock_rpm = fans[0].rpm_min - 105;
|
||||
fan_set_percent_needed(0, 1);
|
||||
TEST_ASSERT(fan_get_rpm_actual(0) == fans[0].rpm_start);
|
||||
/* Now let it turn just under rpm_min. Should be okay there. */
|
||||
mock_rpm = fans[0].rpm_min - 10;
|
||||
fan_set_percent_needed(0, 1);
|
||||
TEST_ASSERT(fan_get_rpm_actual(0) == fans[0].rpm_min);
|
||||
/* Let it go a little faster, still okay */
|
||||
mock_rpm = fans[0].rpm_min + 10;
|
||||
fan_set_percent_needed(0, 1);
|
||||
TEST_ASSERT(fan_get_rpm_actual(0) == fans[0].rpm_min);
|
||||
/* But if it drops too low, it should go back to the start speed */
|
||||
mock_rpm = fans[0].rpm_min - 105;
|
||||
fan_set_percent_needed(0, 1);
|
||||
TEST_ASSERT(fan_get_rpm_actual(0) == fans[0].rpm_start);
|
||||
/* And then relax */
|
||||
fan_set_percent_needed(0, 1);
|
||||
TEST_ASSERT(fan_get_rpm_actual(0) == fans[0].rpm_min);
|
||||
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
void run_test(void)
|
||||
{
|
||||
RUN_TEST(test_fan);
|
||||
|
||||
test_print_result();
|
||||
}
|
||||
17
test/fan.tasklist
Normal file
17
test/fan.tasklist
Normal file
@@ -0,0 +1,17 @@
|
||||
/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
/**
|
||||
* List of enabled tasks in the priority order
|
||||
*
|
||||
* The first one has the lowest priority.
|
||||
*
|
||||
* For each task, use the macro TASK_TEST(n, r, d, s) where :
|
||||
* 'n' in the name of the task
|
||||
* 'r' in the main routine of the task
|
||||
* 'd' in an opaque parameter passed to the routine at startup
|
||||
* 's' is the stack size in bytes; must be a multiple of 8
|
||||
*/
|
||||
#define CONFIG_TEST_TASK_LIST /* No test task */
|
||||
@@ -104,6 +104,10 @@ int board_discharge_on_ac(int enabled);
|
||||
#define I2C_PORT_MASTER 1
|
||||
#endif
|
||||
|
||||
#ifdef TEST_FAN
|
||||
#define CONFIG_FANS 1
|
||||
#endif
|
||||
|
||||
#ifdef TEST_BUTTON
|
||||
#define CONFIG_BUTTON_COUNT 2
|
||||
#define CONFIG_KEYBOARD_PROTOCOL_8042
|
||||
|
||||
Reference in New Issue
Block a user