1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * processor thermal device platform temperature controls
4  * Copyright (c) 2025, Intel Corporation.
5  */
6 
7 /*
8  * Platform temperature controls hardware interface
9  *
10  * The hardware control interface is via MMIO offsets in the processor
11  * thermal device MMIO space. There are three instances of MMIO registers.
12  * All registers are 64 bit wide with RW access.
13  *
14  * Name: PLATFORM_TEMPERATURE_CONTROL
15  * Offsets: 0x5B20, 0x5B28, 0x5B30
16  *
17  *   Bits    Description
18  *   7:0     TARGET_TEMP : Target temperature limit to which the control
19  *           mechanism is regulating. Units: 0.5C.
20  *   8:8     ENABLE: Read current enable status of the feature or enable
21  *           feature.
22  *   11:9    GAIN: Sets the aggressiveness of control loop from 0 to 7
23  *           7 graceful, favors performance at the expense of temperature
24  *           overshoots
25  *           0 aggressive, favors tight regulation over performance
26  *   12:12   TEMPERATURE_OVERRIDE_EN
27  *           When set, hardware will use TEMPERATURE_OVERRIDE values instead
28  *           of reading from corresponding sensor.
29  *   15:13   RESERVED
30  *   23:16   MIN_PERFORMANCE_LEVEL: Minimum Performance level below which the
31  *           there will be no throttling. 0 - all levels of throttling allowed
32  *           including survivability actions. 255 - no throttling allowed.
33  *   31:24   TEMPERATURE_OVERRIDE: Allows SW to override the input temperature.
34  *           hardware will use this value instead of the sensor temperature.
35  *           Units: 0.5C.
36  *   63:32   RESERVED
37  */
38 
39 #include <linux/kernel.h>
40 #include <linux/module.h>
41 #include <linux/pci.h>
42 #include "processor_thermal_device.h"
43 
44 struct mmio_reg {
45 	int bits;
46 	u16 mask;
47 	u16 shift;
48 	u16 units;
49 };
50 
51 #define MAX_ATTR_GROUP_NAME_LEN	32
52 #define PTC_MAX_ATTRS		3
53 
54 struct ptc_data {
55 	u32 offset;
56 	struct attribute_group ptc_attr_group;
57 	struct attribute *ptc_attrs[PTC_MAX_ATTRS];
58 	struct device_attribute temperature_target_attr;
59 	struct device_attribute enable_attr;
60 	char group_name[MAX_ATTR_GROUP_NAME_LEN];
61 };
62 
63 static const struct mmio_reg ptc_mmio_regs[] = {
64 	{ 8, 0xFF, 0, 500}, /* temperature_target, units 0.5C*/
65 	{ 1, 0x01, 8, 0}, /* enable */
66 	{ 3, 0x7, 9, 0}, /* gain */
67 	{ 8, 0xFF, 16, 0}, /* min_performance_level */
68 	{ 1, 0x1, 12, 0}, /* temperature_override_enable */
69 	{ 8, 0xFF, 24, 500}, /* temperature_override, units 0.5C */
70 };
71 
72 #define PTC_MAX_INSTANCES	3
73 
74 /* Unique offset for each PTC instance */
75 static u32 ptc_offsets[PTC_MAX_INSTANCES] = {0x5B20, 0x5B28, 0x5B30};
76 
77 /* These will represent sysfs attribute names */
78 static const char * const ptc_strings[] = {
79 	"temperature_target",
80 	"enable",
81 	NULL
82 };
83 
84 /* Lock to protect concurrent read/write and read-modify-write */
85 static DEFINE_MUTEX(ptc_lock);
86 
87 static ssize_t ptc_mmio_show(struct ptc_data *data, struct device *dev,
88 			     struct device_attribute *attr, char *buf)
89 {
90 	struct pci_dev *pdev = to_pci_dev(dev);
91 	struct proc_thermal_device *proc_priv;
92 	const struct mmio_reg *mmio_regs;
93 	int ret, units;
94 	u64 reg_val;
95 
96 	proc_priv = pci_get_drvdata(pdev);
97 	mmio_regs = ptc_mmio_regs;
98 	ret = match_string(ptc_strings, -1, attr->attr.name);
99 	if (ret < 0)
100 		return ret;
101 
102 	units = mmio_regs[ret].units;
103 
104 	guard(mutex)(&ptc_lock);
105 
106 	reg_val = readq((void __iomem *) (proc_priv->mmio_base + data->offset));
107 	ret = (reg_val >> mmio_regs[ret].shift) & mmio_regs[ret].mask;
108 	if (units)
109 		ret *= units;
110 
111 	return sysfs_emit(buf, "%d\n", ret);
112 }
113 
114 #define PTC_SHOW(suffix)\
115 static ssize_t suffix##_show(struct device *dev,\
116 			     struct device_attribute *attr,\
117 			     char *buf)\
118 {\
119 	struct ptc_data *data = container_of(attr, struct ptc_data, suffix##_attr);\
120 	return ptc_mmio_show(data, dev, attr, buf);\
121 }
122 
123 static void ptc_mmio_write(struct pci_dev *pdev, u32 offset, int index, u32 value)
124 {
125 	struct proc_thermal_device *proc_priv;
126 	u64 mask, reg_val;
127 
128 	proc_priv = pci_get_drvdata(pdev);
129 
130 	mask = GENMASK_ULL(ptc_mmio_regs[index].shift + ptc_mmio_regs[index].bits - 1,
131 			   ptc_mmio_regs[index].shift);
132 
133 	guard(mutex)(&ptc_lock);
134 
135 	reg_val = readq((void __iomem *) (proc_priv->mmio_base + offset));
136 	reg_val &= ~mask;
137 	reg_val |= (value << ptc_mmio_regs[index].shift);
138 	writeq(reg_val, (void __iomem *) (proc_priv->mmio_base + offset));
139 }
140 
141 static int ptc_store(struct ptc_data *data, struct device *dev, struct device_attribute *attr,
142 		     const char *buf,  size_t count)
143 {
144 	struct pci_dev *pdev = to_pci_dev(dev);
145 	unsigned int input;
146 	int ret;
147 
148 	ret = kstrtouint(buf, 10, &input);
149 	if (ret)
150 		return ret;
151 
152 	ret = match_string(ptc_strings, -1, attr->attr.name);
153 	if (ret < 0)
154 		return ret;
155 
156 	if (ptc_mmio_regs[ret].units)
157 		input /= ptc_mmio_regs[ret].units;
158 
159 	if (input > ptc_mmio_regs[ret].mask)
160 		return -EINVAL;
161 
162 	ptc_mmio_write(pdev, data->offset, ret, input);
163 
164 	return count;
165 }
166 
167 #define PTC_STORE(suffix)\
168 static ssize_t suffix##_store(struct device *dev,\
169 			      struct device_attribute *attr,\
170 			      const char *buf, size_t count)\
171 {\
172 	struct ptc_data *data = container_of(attr, struct ptc_data, suffix##_attr);\
173 	return ptc_store(data, dev, attr, buf, count);\
174 }
175 
176 PTC_SHOW(temperature_target);
177 PTC_STORE(temperature_target);
178 PTC_SHOW(enable);
179 PTC_STORE(enable);
180 
181 #define ptc_init_attribute(_name)\
182 	do {\
183 		sysfs_attr_init(&data->_name##_attr.attr);\
184 		data->_name##_attr.show = _name##_show;\
185 		data->_name##_attr.store = _name##_store;\
186 		data->_name##_attr.attr.name = #_name;\
187 		data->_name##_attr.attr.mode = 0644;\
188 	} while (0)
189 
190 static int ptc_create_groups(struct pci_dev *pdev, int instance, struct ptc_data *data)
191 {
192 	int ret, index = 0;
193 
194 	ptc_init_attribute(temperature_target);
195 	ptc_init_attribute(enable);
196 
197 	data->ptc_attrs[index++] = &data->temperature_target_attr.attr;
198 	data->ptc_attrs[index++] = &data->enable_attr.attr;
199 	data->ptc_attrs[index] = NULL;
200 
201 	snprintf(data->group_name, MAX_ATTR_GROUP_NAME_LEN,
202 		"ptc_%d_control", instance);
203 	data->ptc_attr_group.name = data->group_name;
204 	data->ptc_attr_group.attrs = data->ptc_attrs;
205 
206 	ret = sysfs_create_group(&pdev->dev.kobj, &data->ptc_attr_group);
207 
208 	return ret;
209 }
210 
211 static struct ptc_data ptc_instance[PTC_MAX_INSTANCES];
212 
213 int proc_thermal_ptc_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv)
214 {
215 	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_PTC) {
216 		int i;
217 
218 		for (i = 0; i < PTC_MAX_INSTANCES; i++) {
219 			ptc_instance[i].offset = ptc_offsets[i];
220 			ptc_create_groups(pdev, i, &ptc_instance[i]);
221 		}
222 	}
223 
224 	return 0;
225 }
226 EXPORT_SYMBOL_GPL(proc_thermal_ptc_add);
227 
228 void proc_thermal_ptc_remove(struct pci_dev *pdev)
229 {
230 	struct proc_thermal_device *proc_priv = pci_get_drvdata(pdev);
231 
232 	if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_PTC) {
233 		int i;
234 
235 		for (i = 0; i < PTC_MAX_INSTANCES; i++)
236 			sysfs_remove_group(&pdev->dev.kobj, &ptc_instance[i].ptc_attr_group);
237 	}
238 }
239 EXPORT_SYMBOL_GPL(proc_thermal_ptc_remove);
240 
241 MODULE_IMPORT_NS("INT340X_THERMAL");
242 MODULE_LICENSE("GPL");
243 MODULE_DESCRIPTION("Processor Thermal PTC Interface");
244