blob: b1016cd661f3fffbde759086e8683e1c531f743f [file] [log] [blame]
Raul E Rangel9bf32b92021-05-12 17:03:40 -06001/* SPDX-License-Identifier: GPL-2.0-only */
2
3#include <acpi/acpigen.h>
4#include <assert.h>
5#include <commonlib/bsd/helpers.h>
6#include <console/console.h>
7#include <device/device.h>
Elyes Haouasbdd03c22024-05-27 11:20:07 +02008#include <stdio.h>
Raul E Rangel9bf32b92021-05-12 17:03:40 -06009#include <stdlib.h>
10#include <string.h>
11
12#include "chip.h"
13
14#define TZ_DEVICE_PATH "\\_TZ"
15/* These defaults should be good enough for most systems */
16#define DEFAULT_TC1 2
17#define DEFAULT_TC2 5
18#define DEFAULT_TSP 10
19
Nicholas Sudsgaard09a0dc62024-03-10 22:23:40 +090020#define CELSIUS_TO_DECI_KELVIN(temp_c) ((temp_c) * 10 + 2732)
Raul E Rangel9bf32b92021-05-12 17:03:40 -060021#define SECONDS_TO_DECI_SECONDS(s) ((s) * 10)
22
23static const char *thermal_zone_acpi_name(const struct device *dev)
24{
25 char *name;
26
27 if (dev->path.type != DEVICE_PATH_GENERIC)
28 return NULL;
29
30 name = malloc(ACPI_NAME_BUFFER_SIZE);
31 snprintf(name, ACPI_NAME_BUFFER_SIZE, "TM%02X", dev->path.generic.id);
32
33 return name;
34}
35
36static void thermal_zone_fill_ssdt(const struct device *dev)
37{
38 struct drivers_acpi_thermal_zone_config *config = config_of(dev);
39 const char *scope;
40 const char *name;
41
42 assert(dev->path.type == DEVICE_PATH_GENERIC);
43
44 if (config->use_acpi1_thermal_zone_scope)
45 scope = TZ_DEVICE_PATH;
46 else
47 scope = acpi_device_scope(dev);
48
49 name = acpi_device_name(dev);
50
51 assert(name);
52 assert(scope);
53
54 if (!config->temperature_controller) {
55 printk(BIOS_ERR, "%s: missing temperature_controller\n", dev_path(dev));
56 return;
57 }
58
59 printk(BIOS_INFO, "%s.%s: %s at %s\n", scope, name, dev->chip_ops->name, dev_path(dev));
60
61 acpigen_write_scope(scope);
62 acpigen_write_thermal_zone(name);
63
64 if (config->description)
Cliff Huang95e4ffe2023-09-07 09:39:37 -070065 acpigen_write_name_unicode("_STR", config->description);
Raul E Rangel9bf32b92021-05-12 17:03:40 -060066
67 if (config->polling_period)
68 acpigen_write_name_integer(
69 "_TZP", SECONDS_TO_DECI_SECONDS(config->polling_period));
70
71 if (config->critical_temperature)
72 acpigen_write_name_integer(
73 "_CRT", CELSIUS_TO_DECI_KELVIN(config->critical_temperature));
74
75 if (config->hibernate_temperature)
76 acpigen_write_name_integer(
77 "_HOT", CELSIUS_TO_DECI_KELVIN(config->hibernate_temperature));
78
79 if (config->passive_config.temperature) {
80 acpigen_write_name_integer(
81 "_PSV", CELSIUS_TO_DECI_KELVIN(config->passive_config.temperature));
82
83 /*
84 * The linux kernel currently has an artificial limit of 10 on the number of
85 * references that can be returned in a list. If we don't respect this limit,
86 * then the passive threshold won't work.
87 *
88 * See https://source.chromium.org/chromiumos/chromiumos/codesearch/+/main:src/third_party/kernel/v5.10/include/acpi/acpi_bus.h;l=19
89 */
90 acpigen_write_processor_package("_PSL", 0, MIN(10, dev_count_cpu()));
91
92 acpigen_write_name_integer("_TC1", config->passive_config.time_constant_1
93 ?: DEFAULT_TC1);
94 acpigen_write_name_integer("_TC2", config->passive_config.time_constant_2
95 ?: DEFAULT_TC2);
96 acpigen_write_name_integer(
97 "_TSP",
98 SECONDS_TO_DECI_SECONDS(config->passive_config.time_sampling_period
99 ?: DEFAULT_TSP));
100 }
101
102 /*
103 * Method (_TMP) {
104 * Return (<path>.TMP(<sensor_id>))
105 * }
106 */
107 acpigen_write_method_serialized("_TMP", 0);
108 acpigen_emit_byte(RETURN_OP);
109 acpigen_emit_namestring(acpi_device_path_join(config->temperature_controller, "TMP"));
110 acpigen_write_integer(config->sensor_id);
111 acpigen_write_method_end();
112
113 acpigen_write_thermal_zone_end();
114 acpigen_write_scope_end();
115}
116
117static struct device_operations thermal_zone_ops = {
118 .read_resources = noop_read_resources,
119 .set_resources = noop_set_resources,
120 .acpi_name = thermal_zone_acpi_name,
121 .acpi_fill_ssdt = thermal_zone_fill_ssdt,
122};
123
124static void thermal_zone_enable_dev(struct device *dev)
125{
126 dev->ops = &thermal_zone_ops;
127}
128
129struct chip_operations drivers_acpi_thermal_zone_ops = {
Nicholas Sudsgaardbfb11be2024-01-30 09:53:46 +0900130 .name = "ACPI Thermal Zone",
Raul E Rangel9bf32b92021-05-12 17:03:40 -0600131 .enable_dev = thermal_zone_enable_dev,
132};