1
2
3
4
5
6
7#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
8
9#include <linux/module.h>
10#include <linux/slab.h>
11#include <linux/interrupt.h>
12#include <asm/iosf_mbi.h>
13#include "intel_soc_dts_iosf.h"
14
15#define SOC_DTS_OFFSET_ENABLE 0xB0
16#define SOC_DTS_OFFSET_TEMP 0xB1
17
18#define SOC_DTS_OFFSET_PTPS 0xB2
19#define SOC_DTS_OFFSET_PTTS 0xB3
20#define SOC_DTS_OFFSET_PTTSS 0xB4
21#define SOC_DTS_OFFSET_PTMC 0x80
22#define SOC_DTS_TE_AUX0 0xB5
23#define SOC_DTS_TE_AUX1 0xB6
24
25#define SOC_DTS_AUX0_ENABLE_BIT BIT(0)
26#define SOC_DTS_AUX1_ENABLE_BIT BIT(1)
27#define SOC_DTS_CPU_MODULE0_ENABLE_BIT BIT(16)
28#define SOC_DTS_CPU_MODULE1_ENABLE_BIT BIT(17)
29#define SOC_DTS_TE_SCI_ENABLE BIT(9)
30#define SOC_DTS_TE_SMI_ENABLE BIT(10)
31#define SOC_DTS_TE_MSI_ENABLE BIT(11)
32#define SOC_DTS_TE_APICA_ENABLE BIT(14)
33#define SOC_DTS_PTMC_APIC_DEASSERT_BIT BIT(4)
34
35
36#define SOC_DTS_TJMAX_ENCODING 0x7F
37
38
39#define SOC_MAX_DTS_TRIPS 2
40
41
42#define SOC_DTS_TRIP_MASK 0x03
43
44
45#define SOC_MAX_DTS_SENSORS 2
46
47static int get_tj_max(u32 *tj_max)
48{
49 u32 eax, edx;
50 u32 val;
51 int err;
52
53 err = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);
54 if (err)
55 goto err_ret;
56 else {
57 val = (eax >> 16) & 0xff;
58 if (val)
59 *tj_max = val * 1000;
60 else {
61 err = -EINVAL;
62 goto err_ret;
63 }
64 }
65
66 return 0;
67err_ret:
68 *tj_max = 0;
69
70 return err;
71}
72
73static int sys_get_trip_temp(struct thermal_zone_device *tzd, int trip,
74 int *temp)
75{
76 int status;
77 u32 out;
78 struct intel_soc_dts_sensor_entry *dts;
79 struct intel_soc_dts_sensors *sensors;
80
81 dts = tzd->devdata;
82 sensors = dts->sensors;
83 mutex_lock(&sensors->dts_update_lock);
84 status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
85 SOC_DTS_OFFSET_PTPS, &out);
86 mutex_unlock(&sensors->dts_update_lock);
87 if (status)
88 return status;
89
90 out = (out >> (trip * 8)) & SOC_DTS_TJMAX_ENCODING;
91 if (!out)
92 *temp = 0;
93 else
94 *temp = sensors->tj_max - out * 1000;
95
96 return 0;
97}
98
99static int update_trip_temp(struct intel_soc_dts_sensor_entry *dts,
100 int thres_index, int temp,
101 enum thermal_trip_type trip_type)
102{
103 int status;
104 u32 temp_out;
105 u32 out;
106 u32 store_ptps;
107 u32 store_ptmc;
108 u32 store_te_out;
109 u32 te_out;
110 u32 int_enable_bit = SOC_DTS_TE_APICA_ENABLE;
111 struct intel_soc_dts_sensors *sensors = dts->sensors;
112
113 if (sensors->intr_type == INTEL_SOC_DTS_INTERRUPT_MSI)
114 int_enable_bit |= SOC_DTS_TE_MSI_ENABLE;
115
116 temp_out = (sensors->tj_max - temp) / 1000;
117
118 status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
119 SOC_DTS_OFFSET_PTPS, &store_ptps);
120 if (status)
121 return status;
122
123 out = (store_ptps & ~(0xFF << (thres_index * 8)));
124 out |= (temp_out & 0xFF) << (thres_index * 8);
125 status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
126 SOC_DTS_OFFSET_PTPS, out);
127 if (status)
128 return status;
129
130 pr_debug("update_trip_temp PTPS = %x\n", out);
131 status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
132 SOC_DTS_OFFSET_PTMC, &out);
133 if (status)
134 goto err_restore_ptps;
135
136 store_ptmc = out;
137
138 status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
139 SOC_DTS_TE_AUX0 + thres_index,
140 &te_out);
141 if (status)
142 goto err_restore_ptmc;
143
144 store_te_out = te_out;
145
146 out |= (SOC_DTS_CPU_MODULE0_ENABLE_BIT |
147 SOC_DTS_CPU_MODULE1_ENABLE_BIT);
148 if (temp) {
149 if (thres_index)
150 out |= SOC_DTS_AUX1_ENABLE_BIT;
151 else
152 out |= SOC_DTS_AUX0_ENABLE_BIT;
153 te_out |= int_enable_bit;
154 } else {
155 if (thres_index)
156 out &= ~SOC_DTS_AUX1_ENABLE_BIT;
157 else
158 out &= ~SOC_DTS_AUX0_ENABLE_BIT;
159 te_out &= ~int_enable_bit;
160 }
161 status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
162 SOC_DTS_OFFSET_PTMC, out);
163 if (status)
164 goto err_restore_te_out;
165
166 status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
167 SOC_DTS_TE_AUX0 + thres_index,
168 te_out);
169 if (status)
170 goto err_restore_te_out;
171
172 dts->trip_types[thres_index] = trip_type;
173
174 return 0;
175err_restore_te_out:
176 iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
177 SOC_DTS_OFFSET_PTMC, store_te_out);
178err_restore_ptmc:
179 iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
180 SOC_DTS_OFFSET_PTMC, store_ptmc);
181err_restore_ptps:
182 iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
183 SOC_DTS_OFFSET_PTPS, store_ptps);
184
185
186 return status;
187}
188
189static int sys_set_trip_temp(struct thermal_zone_device *tzd, int trip,
190 int temp)
191{
192 struct intel_soc_dts_sensor_entry *dts = tzd->devdata;
193 struct intel_soc_dts_sensors *sensors = dts->sensors;
194 int status;
195
196 if (temp > sensors->tj_max)
197 return -EINVAL;
198
199 mutex_lock(&sensors->dts_update_lock);
200 status = update_trip_temp(tzd->devdata, trip, temp,
201 dts->trip_types[trip]);
202 mutex_unlock(&sensors->dts_update_lock);
203
204 return status;
205}
206
207static int sys_get_trip_type(struct thermal_zone_device *tzd,
208 int trip, enum thermal_trip_type *type)
209{
210 struct intel_soc_dts_sensor_entry *dts;
211
212 dts = tzd->devdata;
213
214 *type = dts->trip_types[trip];
215
216 return 0;
217}
218
219static int sys_get_curr_temp(struct thermal_zone_device *tzd,
220 int *temp)
221{
222 int status;
223 u32 out;
224 struct intel_soc_dts_sensor_entry *dts;
225 struct intel_soc_dts_sensors *sensors;
226
227 dts = tzd->devdata;
228 sensors = dts->sensors;
229 status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
230 SOC_DTS_OFFSET_TEMP, &out);
231 if (status)
232 return status;
233
234 out = (out & dts->temp_mask) >> dts->temp_shift;
235 out -= SOC_DTS_TJMAX_ENCODING;
236 *temp = sensors->tj_max - out * 1000;
237
238 return 0;
239}
240
241static struct thermal_zone_device_ops tzone_ops = {
242 .get_temp = sys_get_curr_temp,
243 .get_trip_temp = sys_get_trip_temp,
244 .get_trip_type = sys_get_trip_type,
245 .set_trip_temp = sys_set_trip_temp,
246};
247
248static int soc_dts_enable(int id)
249{
250 u32 out;
251 int ret;
252
253 ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
254 SOC_DTS_OFFSET_ENABLE, &out);
255 if (ret)
256 return ret;
257
258 if (!(out & BIT(id))) {
259 out |= BIT(id);
260 ret = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
261 SOC_DTS_OFFSET_ENABLE, out);
262 if (ret)
263 return ret;
264 }
265
266 return ret;
267}
268
269static void remove_dts_thermal_zone(struct intel_soc_dts_sensor_entry *dts)
270{
271 if (dts) {
272 iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
273 SOC_DTS_OFFSET_ENABLE, dts->store_status);
274 thermal_zone_device_unregister(dts->tzone);
275 }
276}
277
278static int add_dts_thermal_zone(int id, struct intel_soc_dts_sensor_entry *dts,
279 bool notification_support, int trip_cnt,
280 int read_only_trip_cnt)
281{
282 char name[10];
283 int trip_count = 0;
284 int trip_mask = 0;
285 u32 store_ptps;
286 int ret;
287 int i;
288
289
290 ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
291 SOC_DTS_OFFSET_ENABLE, &dts->store_status);
292 if (ret)
293 goto err_ret;
294
295 dts->id = id;
296 dts->temp_mask = 0x00FF << (id * 8);
297 dts->temp_shift = id * 8;
298 if (notification_support) {
299 trip_count = min(SOC_MAX_DTS_TRIPS, trip_cnt);
300 trip_mask = BIT(trip_count - read_only_trip_cnt) - 1;
301 }
302
303
304 ret = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
305 SOC_DTS_OFFSET_PTPS, &store_ptps);
306 if (ret)
307 trip_mask = 0;
308 else {
309 for (i = 0; i < trip_count; ++i) {
310 if (trip_mask & BIT(i))
311 if (store_ptps & (0xff << (i * 8)))
312 trip_mask &= ~BIT(i);
313 }
314 }
315 dts->trip_mask = trip_mask;
316 dts->trip_count = trip_count;
317 snprintf(name, sizeof(name), "soc_dts%d", id);
318 dts->tzone = thermal_zone_device_register(name,
319 trip_count,
320 trip_mask,
321 dts, &tzone_ops,
322 NULL, 0, 0);
323 if (IS_ERR(dts->tzone)) {
324 ret = PTR_ERR(dts->tzone);
325 goto err_ret;
326 }
327
328 ret = soc_dts_enable(id);
329 if (ret)
330 goto err_enable;
331
332 return 0;
333err_enable:
334 thermal_zone_device_unregister(dts->tzone);
335err_ret:
336 return ret;
337}
338
339int intel_soc_dts_iosf_add_read_only_critical_trip(
340 struct intel_soc_dts_sensors *sensors, int critical_offset)
341{
342 int i, j;
343
344 for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) {
345 for (j = 0; j < sensors->soc_dts[i].trip_count; ++j) {
346 if (!(sensors->soc_dts[i].trip_mask & BIT(j))) {
347 return update_trip_temp(&sensors->soc_dts[i], j,
348 sensors->tj_max - critical_offset,
349 THERMAL_TRIP_CRITICAL);
350 }
351 }
352 }
353
354 return -EINVAL;
355}
356EXPORT_SYMBOL_GPL(intel_soc_dts_iosf_add_read_only_critical_trip);
357
358void intel_soc_dts_iosf_interrupt_handler(struct intel_soc_dts_sensors *sensors)
359{
360 u32 sticky_out;
361 int status;
362 u32 ptmc_out;
363 unsigned long flags;
364
365 spin_lock_irqsave(&sensors->intr_notify_lock, flags);
366
367 status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
368 SOC_DTS_OFFSET_PTMC, &ptmc_out);
369 ptmc_out |= SOC_DTS_PTMC_APIC_DEASSERT_BIT;
370 status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
371 SOC_DTS_OFFSET_PTMC, ptmc_out);
372
373 status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
374 SOC_DTS_OFFSET_PTTSS, &sticky_out);
375 pr_debug("status %d PTTSS %x\n", status, sticky_out);
376 if (sticky_out & SOC_DTS_TRIP_MASK) {
377 int i;
378
379 status = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
380 SOC_DTS_OFFSET_PTTSS, sticky_out);
381 spin_unlock_irqrestore(&sensors->intr_notify_lock, flags);
382
383 for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) {
384 pr_debug("TZD update for zone %d\n", i);
385 thermal_zone_device_update(sensors->soc_dts[i].tzone,
386 THERMAL_EVENT_UNSPECIFIED);
387 }
388 } else
389 spin_unlock_irqrestore(&sensors->intr_notify_lock, flags);
390}
391EXPORT_SYMBOL_GPL(intel_soc_dts_iosf_interrupt_handler);
392
393struct intel_soc_dts_sensors *intel_soc_dts_iosf_init(
394 enum intel_soc_dts_interrupt_type intr_type, int trip_count,
395 int read_only_trip_count)
396{
397 struct intel_soc_dts_sensors *sensors;
398 bool notification;
399 u32 tj_max;
400 int ret;
401 int i;
402
403 if (!iosf_mbi_available())
404 return ERR_PTR(-ENODEV);
405
406 if (!trip_count || read_only_trip_count > trip_count)
407 return ERR_PTR(-EINVAL);
408
409 if (get_tj_max(&tj_max))
410 return ERR_PTR(-EINVAL);
411
412 sensors = kzalloc(sizeof(*sensors), GFP_KERNEL);
413 if (!sensors)
414 return ERR_PTR(-ENOMEM);
415
416 spin_lock_init(&sensors->intr_notify_lock);
417 mutex_init(&sensors->dts_update_lock);
418 sensors->intr_type = intr_type;
419 sensors->tj_max = tj_max;
420 if (intr_type == INTEL_SOC_DTS_INTERRUPT_NONE)
421 notification = false;
422 else
423 notification = true;
424 for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) {
425 sensors->soc_dts[i].sensors = sensors;
426 ret = add_dts_thermal_zone(i, &sensors->soc_dts[i],
427 notification, trip_count,
428 read_only_trip_count);
429 if (ret)
430 goto err_free;
431 }
432
433 for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) {
434 ret = update_trip_temp(&sensors->soc_dts[i], 0, 0,
435 THERMAL_TRIP_PASSIVE);
436 if (ret)
437 goto err_remove_zone;
438
439 ret = update_trip_temp(&sensors->soc_dts[i], 1, 0,
440 THERMAL_TRIP_PASSIVE);
441 if (ret)
442 goto err_remove_zone;
443 }
444
445 return sensors;
446err_remove_zone:
447 for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i)
448 remove_dts_thermal_zone(&sensors->soc_dts[i]);
449
450err_free:
451 kfree(sensors);
452 return ERR_PTR(ret);
453}
454EXPORT_SYMBOL_GPL(intel_soc_dts_iosf_init);
455
456void intel_soc_dts_iosf_exit(struct intel_soc_dts_sensors *sensors)
457{
458 int i;
459
460 for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) {
461 update_trip_temp(&sensors->soc_dts[i], 0, 0, 0);
462 update_trip_temp(&sensors->soc_dts[i], 1, 0, 0);
463 remove_dts_thermal_zone(&sensors->soc_dts[i]);
464 }
465 kfree(sensors);
466}
467EXPORT_SYMBOL_GPL(intel_soc_dts_iosf_exit);
468
469MODULE_LICENSE("GPL v2");
470