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
ptc_mmio_show(struct ptc_data * data,struct device * dev,struct device_attribute * attr,char * buf)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
ptc_mmio_write(struct pci_dev * pdev,u32 offset,int index,u32 value)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
ptc_store(struct ptc_data * data,struct device * dev,struct device_attribute * attr,const char * buf,size_t count)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
ptc_create_groups(struct pci_dev * pdev,int instance,struct ptc_data * data)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
proc_thermal_ptc_add(struct pci_dev * pdev,struct proc_thermal_device * proc_priv)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
proc_thermal_ptc_remove(struct pci_dev * pdev)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