hc
2023-12-11 d2ccde1c8e90d38cee87a1b0309ad2827f3fd30d
kernel/drivers/thermal/armada_thermal.c
....@@ -1,17 +1,8 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * Marvell EBU Armada SoCs thermal sensor driver
34 *
45 * Copyright (C) 2013 Marvell
5
- *
6
- * This software is licensed under the terms of the GNU General Public
7
- * License version 2, as published by the Free Software Foundation, and
8
- * may be copied, distributed, and modified under those terms.
9
- *
10
- * This program is distributed in the hope that it will be useful,
11
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
- * GNU General Public License for more details.
14
- *
156 */
167 #include <linux/device.h>
178 #include <linux/err.h>
....@@ -26,6 +17,9 @@
2617 #include <linux/iopoll.h>
2718 #include <linux/mfd/syscon.h>
2819 #include <linux/regmap.h>
20
+#include <linux/interrupt.h>
21
+
22
+#include "thermal_core.h"
2923
3024 /* Thermal Manager Control and Status Register */
3125 #define PMU_TDC0_SW_RST_MASK (0x1 << 1)
....@@ -57,13 +51,16 @@
5751 #define CONTROL0_TSEN_MODE_EXTERNAL 0x2
5852 #define CONTROL0_TSEN_MODE_MASK 0x3
5953
60
-#define CONTROL1_TSEN_AVG_SHIFT 0
6154 #define CONTROL1_TSEN_AVG_MASK 0x7
6255 #define CONTROL1_EXT_TSEN_SW_RESET BIT(7)
6356 #define CONTROL1_EXT_TSEN_HW_RESETn BIT(8)
57
+#define CONTROL1_TSEN_INT_EN BIT(25)
58
+#define CONTROL1_TSEN_SELECT_OFF 21
59
+#define CONTROL1_TSEN_SELECT_MASK 0x3
6460
6561 #define STATUS_POLL_PERIOD_US 1000
6662 #define STATUS_POLL_TIMEOUT_US 100000
63
+#define OVERHEAT_INT_POLL_DELAY_MS 1000
6764
6865 struct armada_thermal_data;
6966
....@@ -75,7 +72,11 @@
7572 /* serialize temperature reads/updates */
7673 struct mutex update_lock;
7774 struct armada_thermal_data *data;
75
+ struct thermal_zone_device *overheat_sensor;
76
+ int interrupt_source;
7877 int current_channel;
78
+ long current_threshold;
79
+ long current_hysteresis;
7980 };
8081
8182 struct armada_thermal_data {
....@@ -93,12 +94,20 @@
9394 /* Register shift and mask to access the sensor temperature */
9495 unsigned int temp_shift;
9596 unsigned int temp_mask;
97
+ unsigned int thresh_shift;
98
+ unsigned int hyst_shift;
99
+ unsigned int hyst_mask;
96100 u32 is_valid_bit;
97101
98102 /* Syscon access */
99103 unsigned int syscon_control0_off;
100104 unsigned int syscon_control1_off;
101105 unsigned int syscon_status_off;
106
+ unsigned int dfx_irq_cause_off;
107
+ unsigned int dfx_irq_mask_off;
108
+ unsigned int dfx_overheat_irq;
109
+ unsigned int dfx_server_irq_mask_off;
110
+ unsigned int dfx_server_irq_en;
102111
103112 /* One sensor is in the thermal IC, the others are in the CPUs if any */
104113 unsigned int cpu_nr;
....@@ -142,6 +151,9 @@
142151 /* Reset the sensor */
143152 reg |= PMU_TDC0_SW_RST_MASK;
144153
154
+ regmap_write(priv->syscon, data->syscon_control1_off, reg);
155
+
156
+ reg &= ~PMU_TDC0_SW_RST_MASK;
145157 regmap_write(priv->syscon, data->syscon_control1_off, reg);
146158
147159 /* Enable the sensor */
....@@ -255,8 +267,8 @@
255267
256268 /* Average the output value over 2^1 = 2 samples */
257269 regmap_read(priv->syscon, data->syscon_control1_off, &reg);
258
- reg &= ~CONTROL1_TSEN_AVG_MASK << CONTROL1_TSEN_AVG_SHIFT;
259
- reg |= 1 << CONTROL1_TSEN_AVG_SHIFT;
270
+ reg &= ~CONTROL1_TSEN_AVG_MASK;
271
+ reg |= 1;
260272 regmap_write(priv->syscon, data->syscon_control1_off, reg);
261273 }
262274
....@@ -270,6 +282,41 @@
270282 regmap_read(priv->syscon, priv->data->syscon_status_off, &reg);
271283
272284 return reg & priv->data->is_valid_bit;
285
+}
286
+
287
+static void armada_enable_overheat_interrupt(struct armada_thermal_priv *priv)
288
+{
289
+ struct armada_thermal_data *data = priv->data;
290
+ u32 reg;
291
+
292
+ /* Clear DFX temperature IRQ cause */
293
+ regmap_read(priv->syscon, data->dfx_irq_cause_off, &reg);
294
+
295
+ /* Enable DFX Temperature IRQ */
296
+ regmap_read(priv->syscon, data->dfx_irq_mask_off, &reg);
297
+ reg |= data->dfx_overheat_irq;
298
+ regmap_write(priv->syscon, data->dfx_irq_mask_off, reg);
299
+
300
+ /* Enable DFX server IRQ */
301
+ regmap_read(priv->syscon, data->dfx_server_irq_mask_off, &reg);
302
+ reg |= data->dfx_server_irq_en;
303
+ regmap_write(priv->syscon, data->dfx_server_irq_mask_off, reg);
304
+
305
+ /* Enable overheat interrupt */
306
+ regmap_read(priv->syscon, data->syscon_control1_off, &reg);
307
+ reg |= CONTROL1_TSEN_INT_EN;
308
+ regmap_write(priv->syscon, data->syscon_control1_off, reg);
309
+}
310
+
311
+static void __maybe_unused
312
+armada_disable_overheat_interrupt(struct armada_thermal_priv *priv)
313
+{
314
+ struct armada_thermal_data *data = priv->data;
315
+ u32 reg;
316
+
317
+ regmap_read(priv->syscon, data->syscon_control1_off, &reg);
318
+ reg &= ~CONTROL1_TSEN_INT_EN;
319
+ regmap_write(priv->syscon, data->syscon_control1_off, reg);
273320 }
274321
275322 /* There is currently no board with more than one sensor per channel */
....@@ -388,6 +435,14 @@
388435
389436 /* Do the actual reading */
390437 ret = armada_read_sensor(priv, temp);
438
+ if (ret)
439
+ goto unlock_mutex;
440
+
441
+ /*
442
+ * Select back the interrupt source channel from which a potential
443
+ * critical trip point has been set.
444
+ */
445
+ ret = armada_select_channel(priv, priv->interrupt_source);
391446
392447 unlock_mutex:
393448 mutex_unlock(&priv->update_lock);
....@@ -395,9 +450,126 @@
395450 return ret;
396451 }
397452
398
-static struct thermal_zone_of_device_ops of_ops = {
453
+static const struct thermal_zone_of_device_ops of_ops = {
399454 .get_temp = armada_get_temp,
400455 };
456
+
457
+static unsigned int armada_mc_to_reg_temp(struct armada_thermal_data *data,
458
+ unsigned int temp_mc)
459
+{
460
+ s64 b = data->coef_b;
461
+ s64 m = data->coef_m;
462
+ s64 div = data->coef_div;
463
+ unsigned int sample;
464
+
465
+ if (data->inverted)
466
+ sample = div_s64(((temp_mc * div) + b), m);
467
+ else
468
+ sample = div_s64((b - (temp_mc * div)), m);
469
+
470
+ return sample & data->temp_mask;
471
+}
472
+
473
+/*
474
+ * The documentation states:
475
+ * high/low watermark = threshold +/- 0.4761 * 2^(hysteresis + 2)
476
+ * which is the mathematical derivation for:
477
+ * 0x0 <=> 1.9°C, 0x1 <=> 3.8°C, 0x2 <=> 7.6°C, 0x3 <=> 15.2°C
478
+ */
479
+static unsigned int hyst_levels_mc[] = {1900, 3800, 7600, 15200};
480
+
481
+static unsigned int armada_mc_to_reg_hyst(struct armada_thermal_data *data,
482
+ unsigned int hyst_mc)
483
+{
484
+ int i;
485
+
486
+ /*
487
+ * We will always take the smallest possible hysteresis to avoid risking
488
+ * the hardware integrity by enlarging the threshold by +8°C in the
489
+ * worst case.
490
+ */
491
+ for (i = ARRAY_SIZE(hyst_levels_mc) - 1; i > 0; i--)
492
+ if (hyst_mc >= hyst_levels_mc[i])
493
+ break;
494
+
495
+ return i & data->hyst_mask;
496
+}
497
+
498
+static void armada_set_overheat_thresholds(struct armada_thermal_priv *priv,
499
+ int thresh_mc, int hyst_mc)
500
+{
501
+ struct armada_thermal_data *data = priv->data;
502
+ unsigned int threshold = armada_mc_to_reg_temp(data, thresh_mc);
503
+ unsigned int hysteresis = armada_mc_to_reg_hyst(data, hyst_mc);
504
+ u32 ctrl1;
505
+
506
+ regmap_read(priv->syscon, data->syscon_control1_off, &ctrl1);
507
+
508
+ /* Set Threshold */
509
+ if (thresh_mc >= 0) {
510
+ ctrl1 &= ~(data->temp_mask << data->thresh_shift);
511
+ ctrl1 |= threshold << data->thresh_shift;
512
+ priv->current_threshold = thresh_mc;
513
+ }
514
+
515
+ /* Set Hysteresis */
516
+ if (hyst_mc >= 0) {
517
+ ctrl1 &= ~(data->hyst_mask << data->hyst_shift);
518
+ ctrl1 |= hysteresis << data->hyst_shift;
519
+ priv->current_hysteresis = hyst_mc;
520
+ }
521
+
522
+ regmap_write(priv->syscon, data->syscon_control1_off, ctrl1);
523
+}
524
+
525
+static irqreturn_t armada_overheat_isr(int irq, void *blob)
526
+{
527
+ /*
528
+ * Disable the IRQ and continue in thread context (thermal core
529
+ * notification and temperature monitoring).
530
+ */
531
+ disable_irq_nosync(irq);
532
+
533
+ return IRQ_WAKE_THREAD;
534
+}
535
+
536
+static irqreturn_t armada_overheat_isr_thread(int irq, void *blob)
537
+{
538
+ struct armada_thermal_priv *priv = blob;
539
+ int low_threshold = priv->current_threshold - priv->current_hysteresis;
540
+ int temperature;
541
+ u32 dummy;
542
+ int ret;
543
+
544
+ /* Notify the core in thread context */
545
+ thermal_zone_device_update(priv->overheat_sensor,
546
+ THERMAL_EVENT_UNSPECIFIED);
547
+
548
+ /*
549
+ * The overheat interrupt must be cleared by reading the DFX interrupt
550
+ * cause _after_ the temperature has fallen down to the low threshold.
551
+ * Otherwise future interrupts might not be served.
552
+ */
553
+ do {
554
+ msleep(OVERHEAT_INT_POLL_DELAY_MS);
555
+ mutex_lock(&priv->update_lock);
556
+ ret = armada_read_sensor(priv, &temperature);
557
+ mutex_unlock(&priv->update_lock);
558
+ if (ret)
559
+ goto enable_irq;
560
+ } while (temperature >= low_threshold);
561
+
562
+ regmap_read(priv->syscon, priv->data->dfx_irq_cause_off, &dummy);
563
+
564
+ /* Notify the thermal core that the temperature is acceptable again */
565
+ thermal_zone_device_update(priv->overheat_sensor,
566
+ THERMAL_EVENT_UNSPECIFIED);
567
+
568
+enable_irq:
569
+ enable_irq(irq);
570
+
571
+ return IRQ_HANDLED;
572
+}
401573
402574 static const struct armada_thermal_data armadaxp_data = {
403575 .init = armadaxp_init,
....@@ -407,7 +579,7 @@
407579 .coef_m = 10000000ULL,
408580 .coef_div = 13825,
409581 .syscon_status_off = 0xb0,
410
- .syscon_control1_off = 0xd0,
582
+ .syscon_control1_off = 0x2d0,
411583 };
412584
413585 static const struct armada_thermal_data armada370_data = {
....@@ -454,6 +626,9 @@
454626 .is_valid_bit = BIT(16),
455627 .temp_shift = 0,
456628 .temp_mask = 0x3ff,
629
+ .thresh_shift = 3,
630
+ .hyst_shift = 19,
631
+ .hyst_mask = 0x3,
457632 .coef_b = -150000LL,
458633 .coef_m = 423ULL,
459634 .coef_div = 1,
....@@ -462,6 +637,11 @@
462637 .syscon_control0_off = 0x84,
463638 .syscon_control1_off = 0x88,
464639 .syscon_status_off = 0x8C,
640
+ .dfx_irq_cause_off = 0x108,
641
+ .dfx_irq_mask_off = 0x10C,
642
+ .dfx_overheat_irq = BIT(22),
643
+ .dfx_server_irq_mask_off = 0x104,
644
+ .dfx_server_irq_en = BIT(1),
465645 .cpu_nr = 4,
466646 };
467647
....@@ -470,6 +650,9 @@
470650 .is_valid_bit = BIT(10),
471651 .temp_shift = 0,
472652 .temp_mask = 0x3ff,
653
+ .thresh_shift = 16,
654
+ .hyst_shift = 26,
655
+ .hyst_mask = 0x3,
473656 .coef_b = 1172499100ULL,
474657 .coef_m = 2000096ULL,
475658 .coef_div = 4201,
....@@ -477,6 +660,11 @@
477660 .syscon_control0_off = 0x70,
478661 .syscon_control1_off = 0x74,
479662 .syscon_status_off = 0x78,
663
+ .dfx_irq_cause_off = 0x108,
664
+ .dfx_irq_mask_off = 0x10C,
665
+ .dfx_overheat_irq = BIT(20),
666
+ .dfx_server_irq_mask_off = 0x104,
667
+ .dfx_server_irq_en = BIT(1),
480668 };
481669
482670 static const struct of_device_id armada_thermal_id_table[] = {
....@@ -526,39 +714,31 @@
526714
527715 /* First memory region points towards the status register */
528716 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
529
- if (!res)
530
- return -EIO;
531
-
532
- /*
533
- * Edit the resource start address and length to map over all the
534
- * registers, instead of pointing at them one by one.
535
- */
536
- res->start -= data->syscon_status_off;
537
- res->end = res->start + max(data->syscon_status_off,
538
- max(data->syscon_control0_off,
539
- data->syscon_control1_off)) +
540
- sizeof(unsigned int) - 1;
541
-
542717 base = devm_ioremap_resource(&pdev->dev, res);
543718 if (IS_ERR(base))
544719 return PTR_ERR(base);
545720
721
+ /*
722
+ * Fix up from the old individual DT register specification to
723
+ * cover all the registers. We do this by adjusting the ioremap()
724
+ * result, which should be fine as ioremap() deals with pages.
725
+ * However, validate that we do not cross a page boundary while
726
+ * making this adjustment.
727
+ */
728
+ if (((unsigned long)base & ~PAGE_MASK) < data->syscon_status_off)
729
+ return -EINVAL;
730
+ base -= data->syscon_status_off;
731
+
546732 priv->syscon = devm_regmap_init_mmio(&pdev->dev, base,
547733 &armada_thermal_regmap_config);
548
- if (IS_ERR(priv->syscon))
549
- return PTR_ERR(priv->syscon);
550
-
551
- return 0;
734
+ return PTR_ERR_OR_ZERO(priv->syscon);
552735 }
553736
554737 static int armada_thermal_probe_syscon(struct platform_device *pdev,
555738 struct armada_thermal_priv *priv)
556739 {
557740 priv->syscon = syscon_node_to_regmap(pdev->dev.parent->of_node);
558
- if (IS_ERR(priv->syscon))
559
- return PTR_ERR(priv->syscon);
560
-
561
- return 0;
741
+ return PTR_ERR_OR_ZERO(priv->syscon);
562742 }
563743
564744 static void armada_set_sane_name(struct platform_device *pdev,
....@@ -592,6 +772,48 @@
592772 } while (insane_char);
593773 }
594774
775
+/*
776
+ * The IP can manage to trigger interrupts on overheat situation from all the
777
+ * sensors. However, the interrupt source changes along with the last selected
778
+ * source (ie. the last read sensor), which is an inconsistent behavior. Avoid
779
+ * possible glitches by always selecting back only one channel (arbitrarily: the
780
+ * first in the DT which has a critical trip point). We also disable sensor
781
+ * switch during overheat situations.
782
+ */
783
+static int armada_configure_overheat_int(struct armada_thermal_priv *priv,
784
+ struct thermal_zone_device *tz,
785
+ int sensor_id)
786
+{
787
+ /* Retrieve the critical trip point to enable the overheat interrupt */
788
+ const struct thermal_trip *trips = of_thermal_get_trip_points(tz);
789
+ int ret;
790
+ int i;
791
+
792
+ if (!trips)
793
+ return -EINVAL;
794
+
795
+ for (i = 0; i < of_thermal_get_ntrips(tz); i++)
796
+ if (trips[i].type == THERMAL_TRIP_CRITICAL)
797
+ break;
798
+
799
+ if (i == of_thermal_get_ntrips(tz))
800
+ return -EINVAL;
801
+
802
+ ret = armada_select_channel(priv, sensor_id);
803
+ if (ret)
804
+ return ret;
805
+
806
+ armada_set_overheat_thresholds(priv,
807
+ trips[i].temperature,
808
+ trips[i].hysteresis);
809
+ priv->overheat_sensor = tz;
810
+ priv->interrupt_source = sensor_id;
811
+
812
+ armada_enable_overheat_interrupt(priv);
813
+
814
+ return 0;
815
+}
816
+
595817 static int armada_thermal_probe(struct platform_device *pdev)
596818 {
597819 struct thermal_zone_device *tz;
....@@ -599,7 +821,7 @@
599821 struct armada_drvdata *drvdata;
600822 const struct of_device_id *match;
601823 struct armada_thermal_priv *priv;
602
- int sensor_id;
824
+ int sensor_id, irq;
603825 int ret;
604826
605827 match = of_match_device(armada_thermal_id_table, &pdev->dev);
....@@ -652,6 +874,12 @@
652874 return PTR_ERR(tz);
653875 }
654876
877
+ ret = thermal_zone_device_enable(tz);
878
+ if (ret) {
879
+ thermal_zone_device_unregister(tz);
880
+ return ret;
881
+ }
882
+
655883 drvdata->type = LEGACY;
656884 drvdata->data.tz = tz;
657885 platform_set_drvdata(pdev, drvdata);
....@@ -668,6 +896,23 @@
668896 drvdata->type = SYSCON;
669897 drvdata->data.priv = priv;
670898 platform_set_drvdata(pdev, drvdata);
899
+
900
+ irq = platform_get_irq(pdev, 0);
901
+ if (irq == -EPROBE_DEFER)
902
+ return irq;
903
+
904
+ /* The overheat interrupt feature is not mandatory */
905
+ if (irq > 0) {
906
+ ret = devm_request_threaded_irq(&pdev->dev, irq,
907
+ armada_overheat_isr,
908
+ armada_overheat_isr_thread,
909
+ 0, NULL, priv);
910
+ if (ret) {
911
+ dev_err(&pdev->dev, "Cannot request threaded IRQ %d\n",
912
+ irq);
913
+ return ret;
914
+ }
915
+ }
671916
672917 /*
673918 * There is one channel for the IC and one per CPU (if any), each
....@@ -692,8 +937,20 @@
692937 devm_kfree(&pdev->dev, sensor);
693938 continue;
694939 }
940
+
941
+ /*
942
+ * The first channel that has a critical trip point registered
943
+ * in the DT will serve as interrupt source. Others possible
944
+ * critical trip points will simply be ignored by the driver.
945
+ */
946
+ if (irq > 0 && !priv->overheat_sensor)
947
+ armada_configure_overheat_int(priv, tz, sensor->id);
695948 }
696949
950
+ /* Just complain if no overheat interrupt was set up */
951
+ if (!priv->overheat_sensor)
952
+ dev_warn(&pdev->dev, "Overheat interrupt not available\n");
953
+
697954 return 0;
698955 }
699956