drivers/acpi: Add a chip driver to generate thermal zone
Given the following device tree entry: chip drivers/acpi/thermal_zone register "description" = ""CPU"" use chrome_ec as temperature_controller register "sensor_id" = "0" register "polling_period" = "10" register "critical_temperature" = "91" register "passive_config" = "{ .temperature = 85, }" register "use_acpi1_thermal_zone_scope" = "true" device generic 0 on end end It will generate the following: Scope (\_TZ) { ThermalZone (TM00) { Name (_STR, "CPU") // _STR: Description String Name (_RTV, Zero) // _RTV: Relative Temperature Values Name (_TZP, 0x64) // _TZP: Thermal Zone Polling Name (_CRT, 0x0E39) // _CRT: Critical Temperature Name (_PSV, 0x0DFD) // _PSV: Passive Temperature Name (_PSL, Package (0x10) // _PSL: Passive List { \_SB.CP00, \_SB.CP01, \_SB.CP02, \_SB.CP03, \_SB.CP04, \_SB.CP05, \_SB.CP06, \_SB.CP07, \_SB.CP08, \_SB.CP09, }) Name (_TC1, 0x02) // _TC1: Thermal Constant 1 Name (_TC2, 0x05) // _TC2: Thermal Constant 2 Name (_TSP, 0x14) // _TSP: Thermal Sampling Period Method (_TMP, 0, Serialized) // _TMP: Temperature { Return (\_SB.PCI0.LPCB.EC0.CREC.TMP (Zero)) } } } BUG=b:186166365 TEST=Boot guybrush to OS and verify thermal zone works Signed-off-by: Raul E Rangel <rrangel@chromium.org> Change-Id: Iee2a42db749f18eef6c3f73cdbb3441567301e5d Reviewed-on: https://review.coreboot.org/c/coreboot/+/54132 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Karthik Ramasubramanian <kramasub@google.com>
This commit is contained in:
parent
a9efed5fd9
commit
9bf32b9701
|
@ -0,0 +1,7 @@
|
||||||
|
config DRIVERS_ACPI_THERMAL_ZONE
|
||||||
|
bool
|
||||||
|
default n
|
||||||
|
depends on HAVE_ACPI_TABLES
|
||||||
|
help
|
||||||
|
Adds a chip driver that generates ACPI ThermalZones. See the chapter
|
||||||
|
on Thermal Management in the ACPI specification.
|
|
@ -0,0 +1 @@
|
||||||
|
ramstage-$(CONFIG_DRIVERS_ACPI_THERMAL_ZONE) += thermal_zone.c
|
|
@ -0,0 +1,63 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
|
|
||||||
|
#ifndef __DRIVERS_ACPI_THERMAL_ZONE_H__
|
||||||
|
#define __DRIVERS_ACPI_THERMAL_ZONE_H__
|
||||||
|
|
||||||
|
#include <types.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* All temperature units are in Celsius.
|
||||||
|
* All time units are in seconds.
|
||||||
|
*/
|
||||||
|
struct drivers_acpi_thermal_zone_config {
|
||||||
|
/* Description of the thermal zone */
|
||||||
|
const char *description;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Device that will provide the temperature reading
|
||||||
|
*
|
||||||
|
* This device must have an ACPI method named `TMP` that accepts the
|
||||||
|
* sensor ID as the first argument. It must then return an Integer containing the
|
||||||
|
* sensor's temperature in deci-Kelvin.
|
||||||
|
*/
|
||||||
|
DEVTREE_CONST struct device *temperature_controller;
|
||||||
|
|
||||||
|
/* Used to identify the temperature sensor */
|
||||||
|
unsigned int sensor_id;
|
||||||
|
|
||||||
|
/* The polling period in seconds for this thermal zone. */
|
||||||
|
unsigned int polling_period;
|
||||||
|
|
||||||
|
/* The temperature (_CRT) at which the OS must shutdown the system. */
|
||||||
|
unsigned int critical_temperature;
|
||||||
|
|
||||||
|
/* The temperature (_HOT) at which the OS may choose to hibernate the system */
|
||||||
|
unsigned int hibernate_temperature;
|
||||||
|
|
||||||
|
struct acpi_thermal_zone_passive_config {
|
||||||
|
/*
|
||||||
|
* The temperature (_PSV) at which the OS must activate passive cooling (i.e.,
|
||||||
|
* throttle the CPUs).
|
||||||
|
*/
|
||||||
|
unsigned int temperature;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DeltaP[%] = _TC1 * (Tn - Tn-1) + _TC2 * (Tn - Tt)
|
||||||
|
* Where:
|
||||||
|
* Tn = current temperature
|
||||||
|
* Tt = target temperature (_PSV)
|
||||||
|
*
|
||||||
|
* If any of these values are 0, then one of the following defaults will be
|
||||||
|
* used: TC1: 2, TC2: 5, TSP: 10
|
||||||
|
*/
|
||||||
|
unsigned int time_constant_1;
|
||||||
|
unsigned int time_constant_2;
|
||||||
|
unsigned int time_sampling_period;
|
||||||
|
|
||||||
|
} passive_config;
|
||||||
|
|
||||||
|
/* Place the ThermalZone in the \_TZ scope */
|
||||||
|
bool use_acpi1_thermal_zone_scope;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* __DRIVERS_ACPI_THERMAL_ZONE_H__ */
|
|
@ -0,0 +1,131 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
|
|
||||||
|
#include <acpi/acpigen.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <commonlib/bsd/helpers.h>
|
||||||
|
#include <console/console.h>
|
||||||
|
#include <device/device.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "chip.h"
|
||||||
|
|
||||||
|
#define TZ_DEVICE_PATH "\\_TZ"
|
||||||
|
/* These defaults should be good enough for most systems */
|
||||||
|
#define DEFAULT_TC1 2
|
||||||
|
#define DEFAULT_TC2 5
|
||||||
|
#define DEFAULT_TSP 10
|
||||||
|
|
||||||
|
#define CELSIUS_TO_DECI_KELVIN(temp_c) ((temp_c) * 10 + 2731)
|
||||||
|
#define SECONDS_TO_DECI_SECONDS(s) ((s) * 10)
|
||||||
|
|
||||||
|
static const char *thermal_zone_acpi_name(const struct device *dev)
|
||||||
|
{
|
||||||
|
char *name;
|
||||||
|
|
||||||
|
if (dev->path.type != DEVICE_PATH_GENERIC)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
name = malloc(ACPI_NAME_BUFFER_SIZE);
|
||||||
|
snprintf(name, ACPI_NAME_BUFFER_SIZE, "TM%02X", dev->path.generic.id);
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void thermal_zone_fill_ssdt(const struct device *dev)
|
||||||
|
{
|
||||||
|
struct drivers_acpi_thermal_zone_config *config = config_of(dev);
|
||||||
|
const char *scope;
|
||||||
|
const char *name;
|
||||||
|
|
||||||
|
assert(dev->path.type == DEVICE_PATH_GENERIC);
|
||||||
|
|
||||||
|
if (config->use_acpi1_thermal_zone_scope)
|
||||||
|
scope = TZ_DEVICE_PATH;
|
||||||
|
else
|
||||||
|
scope = acpi_device_scope(dev);
|
||||||
|
|
||||||
|
name = acpi_device_name(dev);
|
||||||
|
|
||||||
|
assert(name);
|
||||||
|
assert(scope);
|
||||||
|
|
||||||
|
if (!config->temperature_controller) {
|
||||||
|
printk(BIOS_ERR, "%s: missing temperature_controller\n", dev_path(dev));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printk(BIOS_INFO, "%s.%s: %s at %s\n", scope, name, dev->chip_ops->name, dev_path(dev));
|
||||||
|
|
||||||
|
acpigen_write_scope(scope);
|
||||||
|
acpigen_write_thermal_zone(name);
|
||||||
|
|
||||||
|
if (config->description)
|
||||||
|
acpigen_write_name_string("_STR", config->description);
|
||||||
|
|
||||||
|
if (config->polling_period)
|
||||||
|
acpigen_write_name_integer(
|
||||||
|
"_TZP", SECONDS_TO_DECI_SECONDS(config->polling_period));
|
||||||
|
|
||||||
|
if (config->critical_temperature)
|
||||||
|
acpigen_write_name_integer(
|
||||||
|
"_CRT", CELSIUS_TO_DECI_KELVIN(config->critical_temperature));
|
||||||
|
|
||||||
|
if (config->hibernate_temperature)
|
||||||
|
acpigen_write_name_integer(
|
||||||
|
"_HOT", CELSIUS_TO_DECI_KELVIN(config->hibernate_temperature));
|
||||||
|
|
||||||
|
if (config->passive_config.temperature) {
|
||||||
|
acpigen_write_name_integer(
|
||||||
|
"_PSV", CELSIUS_TO_DECI_KELVIN(config->passive_config.temperature));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The linux kernel currently has an artificial limit of 10 on the number of
|
||||||
|
* references that can be returned in a list. If we don't respect this limit,
|
||||||
|
* then the passive threshold won't work.
|
||||||
|
*
|
||||||
|
* See https://source.chromium.org/chromiumos/chromiumos/codesearch/+/main:src/third_party/kernel/v5.10/include/acpi/acpi_bus.h;l=19
|
||||||
|
*/
|
||||||
|
acpigen_write_processor_package("_PSL", 0, MIN(10, dev_count_cpu()));
|
||||||
|
|
||||||
|
acpigen_write_name_integer("_TC1", config->passive_config.time_constant_1
|
||||||
|
?: DEFAULT_TC1);
|
||||||
|
acpigen_write_name_integer("_TC2", config->passive_config.time_constant_2
|
||||||
|
?: DEFAULT_TC2);
|
||||||
|
acpigen_write_name_integer(
|
||||||
|
"_TSP",
|
||||||
|
SECONDS_TO_DECI_SECONDS(config->passive_config.time_sampling_period
|
||||||
|
?: DEFAULT_TSP));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Method (_TMP) {
|
||||||
|
* Return (<path>.TMP(<sensor_id>))
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
acpigen_write_method_serialized("_TMP", 0);
|
||||||
|
acpigen_emit_byte(RETURN_OP);
|
||||||
|
acpigen_emit_namestring(acpi_device_path_join(config->temperature_controller, "TMP"));
|
||||||
|
acpigen_write_integer(config->sensor_id);
|
||||||
|
acpigen_write_method_end();
|
||||||
|
|
||||||
|
acpigen_write_thermal_zone_end();
|
||||||
|
acpigen_write_scope_end();
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct device_operations thermal_zone_ops = {
|
||||||
|
.read_resources = noop_read_resources,
|
||||||
|
.set_resources = noop_set_resources,
|
||||||
|
.acpi_name = thermal_zone_acpi_name,
|
||||||
|
.acpi_fill_ssdt = thermal_zone_fill_ssdt,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void thermal_zone_enable_dev(struct device *dev)
|
||||||
|
{
|
||||||
|
dev->ops = &thermal_zone_ops;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct chip_operations drivers_acpi_thermal_zone_ops = {
|
||||||
|
CHIP_NAME("ACPI Thermal Zone")
|
||||||
|
.enable_dev = thermal_zone_enable_dev,
|
||||||
|
};
|
Loading…
Reference in New Issue