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