mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-05 22:41:44 +00:00
Problems with existing thermal control loop:
* Not multi-board friendly. thermal.c only supports Link and needs
refactoring. Temp thresholds and fan speeds are hard-coded.
* Only the PECI temp is used to determine the fan speed. Other temp sensors
are ignored.
* Has confusing data structures. Values in the CPU temp thresholds array mix
ACPI thresholds with fan step values.
With this change, the thermal task monitors all temp sensors in order to
perform two completely independent functions:
Function one: Determine if the host needs to be throttled by or informed of
any thermal events.
For thermal events, each temp sensor will have three threshold levels.
TEMP_HOST_WARN
* When any sensor goes above this level, host_throttle_cpu(1) will be called
to ask the CPU to slow itself down.
* When all sensors drop below this level, host_throttle_cpu(0) will be called.
* Exactly AT this level, nothing happens (this provides hysteresis).
TEMP_HOST_HIGH
* When any sensor goes above this level, chipset_throttle_cpu(1) will be
called to slow the CPU down whether it wants to or not.
* When all sensors drop below this level, chipset_throttle_cpu(0) will be
called.
* Exactly AT this level, nothing happens (this provides hysteresis).
TEMP_HOST_SHUTDOWN
* When any sensor is above this level, chipset_force_shutdown() will be
called to halt the CPU.
* Nothing turns the CPU back on again - the user just has to wait for things
to cool off. Pressing the power button too soon will just trigger shutdown
again as soon as the EC can read the host temp.
Function two: Determine the amount of fan cooling needed
For fan cooling, each temp sensor will have two levels.
TEMP_FAN_OFF
* At or below this temperature, no active cooling is needed.
TEMP_FAN_MAX
* At or above this temperature, active cooling should be running at maximum.
The highest level of all temp sensors will be used to request the amount of
active cooling needed. The function pwm_fan_percent_to_rpm() is invoked to
convert the amount of cooling to the target fan RPM.
The default pwm_fan_percent_to_rpm() function converts smoothly between the
configured CONFIG_PWM_FAN_RPM_MIN and CONFIG_PWM_FAN_RPM_MAX for percentages
between 1 and 100. 0% means "off".
The default function probably provide the smoothest and quietest behavior,
but individual boards can provide their own pwm_fan_percent_to_rpm() to
implement whatever curves, hysteresis, feedback, or other hackery they wish.
BUG=chrome-os-partner:20805
BRANCH=none
TEST=manual
Compile-time test with
make BOARD=falco runtests
On the EC console, the existing fan commands should work correctly:
faninfo - display the fan state
fanduty NUM - force the fan PWM to the specified percentage (0-100)
fanset RPM - force the fan to the specified RPM
fanset NUM% - force the fan to the specified percentage (0-100) between
its configured minimum and maximum speeds from board.h
(CONFIG_PWM_FAN_RPM_MIN and CONFIG_PWM_FAN_RPM_MAX)
fanauto - let the EC control the fan automatically
You can test the default pwm_fan_percent_to_rpm() with
fanset 1%
faninfo
The fan should be turning at CONFIG_PWM_FAN_RPM_MIN. Let the EC control it
automatically again with
fanauto
Also on the EC console, the thermal settings can be examined or changed:
> temps
PECI : 327 K = 54 C
ECInternal : 320 K = 47 C
G781Internal : 319 K = 46 C
G781External : 318 K = 45 C
>
> thermalget
sensor warn high shutdown fan_off fan_max name
0 373 387 383 333 363 PECI
1 0 0 0 0 0 ECInternal
2 0 0 0 0 0 G781Internal
3 0 0 0 0 0 G781External
>
> help thermalset
Usage: thermalset sensor warn [high [shutdown [fan_off [fan_max]]]]
set thermal parameters (-1 to skip)
>
> thermalset 2 -1 -1 999
sensor warn high shutdown fan_off fan_max name
0 373 387 383 333 363 PECI
1 0 0 0 0 0 ECInternal
2 0 0 999 0 0 G781Internal
3 0 0 0 0 0 G781External
>
From the host, ectool can be used to get and set these parameters with
nearly identical commands:
ectool thermalget
ectool thermalset 2 -1 -1 999
Change-Id: Idb27977278f766826045fb7d41929953ec6b1cca
Signed-off-by: Bill Richardson <wfrichar@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/66688
Reviewed-by: Randall Spangler <rspangler@chromium.org>
217 lines
5.5 KiB
C
217 lines
5.5 KiB
C
/* Copyright (c) 2013 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.
|
|
*/
|
|
|
|
/* System hooks for Chrome EC */
|
|
|
|
#ifndef __CROS_EC_HOOKS_H
|
|
#define __CROS_EC_HOOKS_H
|
|
|
|
#include "common.h"
|
|
|
|
enum hook_priority {
|
|
/* Generic values across all hooks */
|
|
HOOK_PRIO_FIRST = 1, /* Highest priority */
|
|
HOOK_PRIO_DEFAULT = 5000, /* Default priority */
|
|
HOOK_PRIO_LAST = 9999, /* Lowest priority */
|
|
|
|
/* Specific hook vales for HOOK_INIT */
|
|
/* DMA inits before ADC, I2C, SPI */
|
|
HOOK_PRIO_INIT_DMA = HOOK_PRIO_FIRST + 1,
|
|
/* LPC inits before modules which need memory-mapped I/O */
|
|
HOOK_PRIO_INIT_LPC = HOOK_PRIO_FIRST + 1,
|
|
/* Chipset inits before modules which need to know its initial state. */
|
|
HOOK_PRIO_INIT_CHIPSET = HOOK_PRIO_FIRST + 2,
|
|
/* Lid switch inits before power button */
|
|
HOOK_PRIO_INIT_LID = HOOK_PRIO_FIRST + 3,
|
|
/* Power button inits before chipset and switch */
|
|
HOOK_PRIO_INIT_POWER_BUTTON = HOOK_PRIO_FIRST + 4,
|
|
|
|
/* Specific values to lump temperature-related hooks together */
|
|
HOOK_PRIO_TEMP_SENSOR = 6000,
|
|
/* After all sensors have been polled */
|
|
HOOK_PRIO_TEMP_SENSOR_DONE = HOOK_PRIO_TEMP_SENSOR + 1,
|
|
};
|
|
|
|
enum hook_type {
|
|
/*
|
|
* System initialization.
|
|
*
|
|
* Hook routines are called from main(), after all hard-coded inits,
|
|
* before task scheduling is enabled.
|
|
*/
|
|
HOOK_INIT = 0,
|
|
|
|
/*
|
|
* System clock changed frequency.
|
|
*
|
|
* Hook routines are called from the context which initiates the
|
|
* frequency change.
|
|
*/
|
|
HOOK_FREQ_CHANGE,
|
|
|
|
/*
|
|
* About to jump to another image. Modules which need to preserve data
|
|
* across such a jump should save it here and restore it in HOOK_INIT.
|
|
*
|
|
* Hook routines are called from the context which initiates the jump,
|
|
* WITH INTERRUPTS DISABLED.
|
|
*/
|
|
HOOK_SYSJUMP,
|
|
|
|
/*
|
|
* Initialization for components such as PMU to be done before host
|
|
* chipset/AP starts up.
|
|
*
|
|
* Hook routines are called from the chipset task.
|
|
*/
|
|
HOOK_CHIPSET_PRE_INIT,
|
|
|
|
/* System is starting up. All suspend rails are now on.
|
|
*
|
|
* Hook routines are called from the chipset task.
|
|
*/
|
|
HOOK_CHIPSET_STARTUP,
|
|
|
|
/*
|
|
* System is resuming from suspend, or booting and has reached the
|
|
* point where all voltage rails are on.
|
|
*
|
|
* Hook routines are called from the chipset task.
|
|
*/
|
|
HOOK_CHIPSET_RESUME,
|
|
|
|
/*
|
|
* System is suspending, or shutting down; all voltage rails are still
|
|
* on.
|
|
*
|
|
* Hook routines are called from the chipset task.
|
|
*/
|
|
HOOK_CHIPSET_SUSPEND,
|
|
|
|
/*
|
|
* System is shutting down. All suspend rails are still on.
|
|
*
|
|
* Hook routines are called from the chipset task.
|
|
*/
|
|
HOOK_CHIPSET_SHUTDOWN,
|
|
|
|
/*
|
|
* AC power plugged in or removed.
|
|
*
|
|
* Hook routines are called from the TICK task.
|
|
*/
|
|
HOOK_AC_CHANGE,
|
|
|
|
/*
|
|
* Lid opened or closed. Based on debounced lid state, not raw lid
|
|
* GPIO input.
|
|
*
|
|
* Hook routines are called from the TICK task.
|
|
*/
|
|
HOOK_LID_CHANGE,
|
|
|
|
/*
|
|
* Power button pressed or released. Based on debounced power button
|
|
* state, not raw GPIO input.
|
|
*
|
|
* Hook routines are called from the TICK task.
|
|
*/
|
|
HOOK_POWER_BUTTON_CHANGE,
|
|
|
|
/*
|
|
* Charge state machine status changed.
|
|
*
|
|
* Hook routines are called from the charger task.
|
|
*/
|
|
HOOK_CHARGE_STATE_CHANGE,
|
|
|
|
/*
|
|
* Periodic tick, every HOOK_TICK_INTERVAL.
|
|
*
|
|
* Hook routines will be called from the TICK task.
|
|
*/
|
|
HOOK_TICK,
|
|
|
|
/*
|
|
* Periodic tick, every second.
|
|
*
|
|
* Hook routines will be called from the TICK task.
|
|
*/
|
|
HOOK_SECOND,
|
|
};
|
|
|
|
struct hook_data {
|
|
/* Hook processing routine. */
|
|
void (*routine)(void);
|
|
/* Priority; low numbers = higher priority. */
|
|
int priority;
|
|
};
|
|
|
|
/**
|
|
* Initialize the hooks library.
|
|
*/
|
|
void hook_init(void);
|
|
|
|
/**
|
|
* Call all the hook routines of a specified type.
|
|
*
|
|
* @param type Type of hook routines to call.
|
|
*/
|
|
void hook_notify(enum hook_type type);
|
|
|
|
/**
|
|
* Start a timer to call a deferred routine.
|
|
*
|
|
* The routine will be called after at least the specified delay, in the
|
|
* context of the hook task.
|
|
*
|
|
* @param routine Routine to call; must have been declared with
|
|
* DECLARE_DEFERRED().
|
|
* @param us Delay in microseconds until routine will be called.
|
|
* If the routine is already pending, subsequent calls
|
|
* will change the delay. Pass us=0 to call as soon as
|
|
* possible, or -1 to cancel the deferred call.
|
|
*
|
|
* @return non-zero if error.
|
|
*/
|
|
int hook_call_deferred(void (*routine)(void), int us);
|
|
|
|
/**
|
|
* Register a hook routine.
|
|
*
|
|
* @param hooktype Type of hook for routine (enum hook_type)
|
|
* @param routine Hook routine, with prototype void routine(void)
|
|
* @param priority Priority for determining when routine is called vs.
|
|
* other hook routines; should be between HOOK_PRIO_FIRST
|
|
* and HOOK_PRIO_LAST, and should be HOOK_PRIO_DEFAULT
|
|
* unless there's a compelling reason to care about the
|
|
* order in which hooks are called.
|
|
*/
|
|
#define DECLARE_HOOK(hooktype, routine, priority) \
|
|
const struct hook_data __hook_##hooktype##_##routine \
|
|
__attribute__((section(".rodata." #hooktype))) \
|
|
= {routine, priority}
|
|
|
|
|
|
struct deferred_data {
|
|
/* Deferred function pointer */
|
|
void (*routine)(void);
|
|
};
|
|
|
|
/**
|
|
* Register a deferred function call.
|
|
*
|
|
* Note that if you declare a bunch of these, you may need to override
|
|
* DEFERRABLE_MAX_COUNT in your board.h.
|
|
*
|
|
* @param routine Function pointer, with prototype void routine(void)
|
|
*/
|
|
#define DECLARE_DEFERRED(routine) \
|
|
const struct deferred_data __deferred_##routine \
|
|
__attribute__((section(".rodata.deferred"))) \
|
|
= {routine}
|
|
|
|
#endif /* __CROS_EC_HOOKS_H */
|