diff options
author | Raul E Rangel <rrangel@chromium.org> | 2021-05-12 17:03:40 -0600 |
---|---|---|
committer | Patrick Georgi <pgeorgi@google.com> | 2021-05-20 08:01:11 +0000 |
commit | 9bf32b9701ddabb3a584f47247416b4a16d1902b (patch) | |
tree | 6f10748d6984aa7a88577307a2ef8f6ebb6353a1 /src/drivers/acpi/thermal_zone | |
parent | a9efed5fd90534b20b6739fa24e5a6339f67b827 (diff) |
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>
Diffstat (limited to 'src/drivers/acpi/thermal_zone')
-rw-r--r-- | src/drivers/acpi/thermal_zone/Kconfig | 7 | ||||
-rw-r--r-- | src/drivers/acpi/thermal_zone/Makefile.inc | 1 | ||||
-rw-r--r-- | src/drivers/acpi/thermal_zone/chip.h | 63 | ||||
-rw-r--r-- | src/drivers/acpi/thermal_zone/thermal_zone.c | 131 |
4 files changed, 202 insertions, 0 deletions
diff --git a/src/drivers/acpi/thermal_zone/Kconfig b/src/drivers/acpi/thermal_zone/Kconfig new file mode 100644 index 0000000000..5deace4c50 --- /dev/null +++ b/src/drivers/acpi/thermal_zone/Kconfig @@ -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. diff --git a/src/drivers/acpi/thermal_zone/Makefile.inc b/src/drivers/acpi/thermal_zone/Makefile.inc new file mode 100644 index 0000000000..0a15b91667 --- /dev/null +++ b/src/drivers/acpi/thermal_zone/Makefile.inc @@ -0,0 +1 @@ +ramstage-$(CONFIG_DRIVERS_ACPI_THERMAL_ZONE) += thermal_zone.c diff --git a/src/drivers/acpi/thermal_zone/chip.h b/src/drivers/acpi/thermal_zone/chip.h new file mode 100644 index 0000000000..5792e4c961 --- /dev/null +++ b/src/drivers/acpi/thermal_zone/chip.h @@ -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__ */ diff --git a/src/drivers/acpi/thermal_zone/thermal_zone.c b/src/drivers/acpi/thermal_zone/thermal_zone.c new file mode 100644 index 0000000000..1a52997607 --- /dev/null +++ b/src/drivers/acpi/thermal_zone/thermal_zone.c @@ -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, +}; |