hc
2023-12-11 d2ccde1c8e90d38cee87a1b0309ad2827f3fd30d
kernel/drivers/thermal/tegra/soctherm.c
....@@ -1,5 +1,6 @@
1
+// SPDX-License-Identifier: GPL-2.0
12 /*
2
- * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
3
+ * Copyright (c) 2014 - 2018, NVIDIA CORPORATION. All rights reserved.
34 *
45 * Author:
56 * Mikko Perttunen <mperttunen@nvidia.com>
....@@ -22,6 +23,8 @@
2223 #include <linux/err.h>
2324 #include <linux/interrupt.h>
2425 #include <linux/io.h>
26
+#include <linux/irq.h>
27
+#include <linux/irqdomain.h>
2528 #include <linux/module.h>
2629 #include <linux/of.h>
2730 #include <linux/platform_device.h>
....@@ -85,11 +88,50 @@
8588 #define THERMCTL_LVL0_UP_STATS 0x10
8689 #define THERMCTL_LVL0_DN_STATS 0x14
8790
91
+#define THERMCTL_INTR_STATUS 0x84
92
+
93
+#define TH_INTR_MD0_MASK BIT(25)
94
+#define TH_INTR_MU0_MASK BIT(24)
95
+#define TH_INTR_GD0_MASK BIT(17)
96
+#define TH_INTR_GU0_MASK BIT(16)
97
+#define TH_INTR_CD0_MASK BIT(9)
98
+#define TH_INTR_CU0_MASK BIT(8)
99
+#define TH_INTR_PD0_MASK BIT(1)
100
+#define TH_INTR_PU0_MASK BIT(0)
101
+#define TH_INTR_IGNORE_MASK 0xFCFCFCFC
102
+
88103 #define THERMCTL_STATS_CTL 0x94
89104 #define STATS_CTL_CLR_DN 0x8
90105 #define STATS_CTL_EN_DN 0x4
91106 #define STATS_CTL_CLR_UP 0x2
92107 #define STATS_CTL_EN_UP 0x1
108
+
109
+#define OC1_CFG 0x310
110
+#define OC1_CFG_LONG_LATENCY_MASK BIT(6)
111
+#define OC1_CFG_HW_RESTORE_MASK BIT(5)
112
+#define OC1_CFG_PWR_GOOD_MASK_MASK BIT(4)
113
+#define OC1_CFG_THROTTLE_MODE_MASK (0x3 << 2)
114
+#define OC1_CFG_ALARM_POLARITY_MASK BIT(1)
115
+#define OC1_CFG_EN_THROTTLE_MASK BIT(0)
116
+
117
+#define OC1_CNT_THRESHOLD 0x314
118
+#define OC1_THROTTLE_PERIOD 0x318
119
+#define OC1_ALARM_COUNT 0x31c
120
+#define OC1_FILTER 0x320
121
+#define OC1_STATS 0x3a8
122
+
123
+#define OC_INTR_STATUS 0x39c
124
+#define OC_INTR_ENABLE 0x3a0
125
+#define OC_INTR_DISABLE 0x3a4
126
+#define OC_STATS_CTL 0x3c4
127
+#define OC_STATS_CTL_CLR_ALL 0x2
128
+#define OC_STATS_CTL_EN_ALL 0x1
129
+
130
+#define OC_INTR_OC1_MASK BIT(0)
131
+#define OC_INTR_OC2_MASK BIT(1)
132
+#define OC_INTR_OC3_MASK BIT(2)
133
+#define OC_INTR_OC4_MASK BIT(3)
134
+#define OC_INTR_OC5_MASK BIT(4)
93135
94136 #define THROT_GLOBAL_CFG 0x400
95137 #define THROT_GLOBAL_ENB_MASK BIT(0)
....@@ -160,6 +202,15 @@
160202 /* get dividend from the depth */
161203 #define THROT_DEPTH_DIVIDEND(depth) ((256 * (100 - (depth)) / 100) - 1)
162204
205
+/* gk20a nv_therm interface N:3 Mapping. Levels defined in tegra124-soctherm.h
206
+ * level vector
207
+ * NONE 3'b000
208
+ * LOW 3'b001
209
+ * MED 3'b011
210
+ * HIGH 3'b111
211
+ */
212
+#define THROT_LEVEL_TO_DEPTH(level) ((0x1 << (level)) - 1)
213
+
163214 /* get THROT_PSKIP_xxx offset per LIGHT/HEAVY throt and CPU/GPU dev */
164215 #define THROT_OFFSET 0x30
165216 #define THROT_PSKIP_CTRL(throt, dev) (THROT_PSKIP_CTRL_LITE_CPU + \
....@@ -173,6 +224,25 @@
173224 #define THROT_DELAY_CTRL(throt) (THROT_DELAY_LITE + \
174225 (THROT_OFFSET * throt))
175226
227
+#define ALARM_OFFSET 0x14
228
+#define ALARM_CFG(throt) (OC1_CFG + \
229
+ (ALARM_OFFSET * (throt - THROTTLE_OC1)))
230
+
231
+#define ALARM_CNT_THRESHOLD(throt) (OC1_CNT_THRESHOLD + \
232
+ (ALARM_OFFSET * (throt - THROTTLE_OC1)))
233
+
234
+#define ALARM_THROTTLE_PERIOD(throt) (OC1_THROTTLE_PERIOD + \
235
+ (ALARM_OFFSET * (throt - THROTTLE_OC1)))
236
+
237
+#define ALARM_ALARM_COUNT(throt) (OC1_ALARM_COUNT + \
238
+ (ALARM_OFFSET * (throt - THROTTLE_OC1)))
239
+
240
+#define ALARM_FILTER(throt) (OC1_FILTER + \
241
+ (ALARM_OFFSET * (throt - THROTTLE_OC1)))
242
+
243
+#define ALARM_STATS(throt) (OC1_STATS + \
244
+ (4 * (throt - THROTTLE_OC1)))
245
+
176246 /* get CCROC_THROT_PSKIP_xxx offset per HIGH/MED/LOW vect*/
177247 #define CCROC_THROT_OFFSET 0x0c
178248 #define CCROC_THROT_PSKIP_CTRL_CPU_REG(vect) (CCROC_THROT_PSKIP_CTRL_CPU + \
....@@ -184,13 +254,30 @@
184254 #define THERMCTL_LVL_REGS_SIZE 0x20
185255 #define THERMCTL_LVL_REG(rg, lv) ((rg) + ((lv) * THERMCTL_LVL_REGS_SIZE))
186256
257
+#define OC_THROTTLE_MODE_DISABLED 0
258
+#define OC_THROTTLE_MODE_BRIEF 2
259
+
187260 static const int min_low_temp = -127000;
188261 static const int max_high_temp = 127000;
189262
190263 enum soctherm_throttle_id {
191264 THROTTLE_LIGHT = 0,
192265 THROTTLE_HEAVY,
266
+ THROTTLE_OC1,
267
+ THROTTLE_OC2,
268
+ THROTTLE_OC3,
269
+ THROTTLE_OC4,
270
+ THROTTLE_OC5, /* OC5 is reserved */
193271 THROTTLE_SIZE,
272
+};
273
+
274
+enum soctherm_oc_irq_id {
275
+ TEGRA_SOC_OC_IRQ_1,
276
+ TEGRA_SOC_OC_IRQ_2,
277
+ TEGRA_SOC_OC_IRQ_3,
278
+ TEGRA_SOC_OC_IRQ_4,
279
+ TEGRA_SOC_OC_IRQ_5,
280
+ TEGRA_SOC_OC_IRQ_MAX,
194281 };
195282
196283 enum soctherm_throttle_dev_id {
....@@ -202,6 +289,11 @@
202289 static const char *const throt_names[] = {
203290 [THROTTLE_LIGHT] = "light",
204291 [THROTTLE_HEAVY] = "heavy",
292
+ [THROTTLE_OC1] = "oc1",
293
+ [THROTTLE_OC2] = "oc2",
294
+ [THROTTLE_OC3] = "oc3",
295
+ [THROTTLE_OC4] = "oc4",
296
+ [THROTTLE_OC5] = "oc5",
205297 };
206298
207299 struct tegra_soctherm;
....@@ -213,12 +305,23 @@
213305 const struct tegra_tsensor_group *sg;
214306 };
215307
308
+struct soctherm_oc_cfg {
309
+ u32 active_low;
310
+ u32 throt_period;
311
+ u32 alarm_cnt_thresh;
312
+ u32 alarm_filter;
313
+ u32 mode;
314
+ bool intr_en;
315
+};
316
+
216317 struct soctherm_throt_cfg {
217318 const char *name;
218319 unsigned int id;
219320 u8 priority;
220321 u8 cpu_throt_level;
221322 u32 cpu_throt_depth;
323
+ u32 gpu_throt_level;
324
+ struct soctherm_oc_cfg oc_cfg;
222325 struct thermal_cooling_device *cdev;
223326 bool init;
224327 };
....@@ -231,6 +334,9 @@
231334 void __iomem *clk_regs;
232335 void __iomem *ccroc_regs;
233336
337
+ int thermal_irq;
338
+ int edp_irq;
339
+
234340 u32 *calib;
235341 struct thermal_zone_device **thermctl_tzs;
236342 struct tegra_soctherm_soc *soc;
....@@ -238,12 +344,23 @@
238344 struct soctherm_throt_cfg throt_cfgs[THROTTLE_SIZE];
239345
240346 struct dentry *debugfs_dir;
347
+
348
+ struct mutex thermctl_lock;
241349 };
350
+
351
+struct soctherm_oc_irq_chip_data {
352
+ struct mutex irq_lock; /* serialize OC IRQs */
353
+ struct irq_chip irq_chip;
354
+ struct irq_domain *domain;
355
+ int irq_enable;
356
+};
357
+
358
+static struct soctherm_oc_irq_chip_data soc_irq_cdata;
242359
243360 /**
244361 * ccroc_writel() - writes a value to a CCROC register
245362 * @ts: pointer to a struct tegra_soctherm
246
- * @v: the value to write
363
+ * @value: the value to write
247364 * @reg: the register offset
248365 *
249366 * Writes @v to @reg. No return value.
....@@ -318,6 +435,7 @@
318435
319436 /**
320437 * enforce_temp_range() - check and enforce temperature range [min, max]
438
+ * @dev: struct device * of the SOC_THERM instance
321439 * @trip_temp: the trip temperature to check
322440 *
323441 * Checks and enforces the permitted temperature range that SOC_THERM
....@@ -446,6 +564,24 @@
446564 return NULL;
447565 }
448566
567
+static int tsensor_group_thermtrip_get(struct tegra_soctherm *ts, int id)
568
+{
569
+ int i, temp = min_low_temp;
570
+ struct tsensor_group_thermtrips *tt = ts->soc->thermtrips;
571
+
572
+ if (id >= TEGRA124_SOCTHERM_SENSOR_NUM)
573
+ return temp;
574
+
575
+ if (tt) {
576
+ for (i = 0; i < ts->soc->num_ttgs; i++) {
577
+ if (tt[i].id == id)
578
+ return tt[i].temp;
579
+ }
580
+ }
581
+
582
+ return temp;
583
+}
584
+
449585 static int tegra_thermctl_set_trip_temp(void *data, int trip, int temp)
450586 {
451587 struct tegra_thermctl_zone *zone = data;
....@@ -464,7 +600,16 @@
464600 return ret;
465601
466602 if (type == THERMAL_TRIP_CRITICAL) {
467
- return thermtrip_program(dev, sg, temp);
603
+ /*
604
+ * If thermtrips property is set in DT,
605
+ * doesn't need to program critical type trip to HW,
606
+ * if not, program critical trip to HW.
607
+ */
608
+ if (min_low_temp == tsensor_group_thermtrip_get(ts, sg->id))
609
+ return thermtrip_program(dev, sg, temp);
610
+ else
611
+ return 0;
612
+
468613 } else if (type == THERMAL_TRIP_HOT) {
469614 int i;
470615
....@@ -488,9 +633,91 @@
488633 return 0;
489634 }
490635
636
+static int tegra_thermctl_get_trend(void *data, int trip,
637
+ enum thermal_trend *trend)
638
+{
639
+ struct tegra_thermctl_zone *zone = data;
640
+ struct thermal_zone_device *tz = zone->tz;
641
+ int trip_temp, temp, last_temp, ret;
642
+
643
+ if (!tz)
644
+ return -EINVAL;
645
+
646
+ ret = tz->ops->get_trip_temp(zone->tz, trip, &trip_temp);
647
+ if (ret)
648
+ return ret;
649
+
650
+ temp = READ_ONCE(tz->temperature);
651
+ last_temp = READ_ONCE(tz->last_temperature);
652
+
653
+ if (temp > trip_temp) {
654
+ if (temp >= last_temp)
655
+ *trend = THERMAL_TREND_RAISING;
656
+ else
657
+ *trend = THERMAL_TREND_STABLE;
658
+ } else if (temp < trip_temp) {
659
+ *trend = THERMAL_TREND_DROPPING;
660
+ } else {
661
+ *trend = THERMAL_TREND_STABLE;
662
+ }
663
+
664
+ return 0;
665
+}
666
+
667
+static void thermal_irq_enable(struct tegra_thermctl_zone *zn)
668
+{
669
+ u32 r;
670
+
671
+ /* multiple zones could be handling and setting trips at once */
672
+ mutex_lock(&zn->ts->thermctl_lock);
673
+ r = readl(zn->ts->regs + THERMCTL_INTR_ENABLE);
674
+ r = REG_SET_MASK(r, zn->sg->thermctl_isr_mask, TH_INTR_UP_DN_EN);
675
+ writel(r, zn->ts->regs + THERMCTL_INTR_ENABLE);
676
+ mutex_unlock(&zn->ts->thermctl_lock);
677
+}
678
+
679
+static void thermal_irq_disable(struct tegra_thermctl_zone *zn)
680
+{
681
+ u32 r;
682
+
683
+ /* multiple zones could be handling and setting trips at once */
684
+ mutex_lock(&zn->ts->thermctl_lock);
685
+ r = readl(zn->ts->regs + THERMCTL_INTR_DISABLE);
686
+ r = REG_SET_MASK(r, zn->sg->thermctl_isr_mask, 0);
687
+ writel(r, zn->ts->regs + THERMCTL_INTR_DISABLE);
688
+ mutex_unlock(&zn->ts->thermctl_lock);
689
+}
690
+
691
+static int tegra_thermctl_set_trips(void *data, int lo, int hi)
692
+{
693
+ struct tegra_thermctl_zone *zone = data;
694
+ u32 r;
695
+
696
+ thermal_irq_disable(zone);
697
+
698
+ r = readl(zone->ts->regs + zone->sg->thermctl_lvl0_offset);
699
+ r = REG_SET_MASK(r, THERMCTL_LVL0_CPU0_EN_MASK, 0);
700
+ writel(r, zone->ts->regs + zone->sg->thermctl_lvl0_offset);
701
+
702
+ lo = enforce_temp_range(zone->dev, lo) / zone->ts->soc->thresh_grain;
703
+ hi = enforce_temp_range(zone->dev, hi) / zone->ts->soc->thresh_grain;
704
+ dev_dbg(zone->dev, "%s hi:%d, lo:%d\n", __func__, hi, lo);
705
+
706
+ r = REG_SET_MASK(r, zone->sg->thermctl_lvl0_up_thresh_mask, hi);
707
+ r = REG_SET_MASK(r, zone->sg->thermctl_lvl0_dn_thresh_mask, lo);
708
+ r = REG_SET_MASK(r, THERMCTL_LVL0_CPU0_EN_MASK, 1);
709
+ writel(r, zone->ts->regs + zone->sg->thermctl_lvl0_offset);
710
+
711
+ thermal_irq_enable(zone);
712
+
713
+ return 0;
714
+}
715
+
491716 static const struct thermal_zone_of_device_ops tegra_of_thermal_ops = {
492717 .get_temp = tegra_thermctl_get_temp,
493718 .set_trip_temp = tegra_thermctl_set_trip_temp,
719
+ .get_trend = tegra_thermctl_get_trend,
720
+ .set_trips = tegra_thermctl_set_trips,
494721 };
495722
496723 static int get_hot_temp(struct thermal_zone_device *tz, int *trip, int *temp)
....@@ -521,9 +748,12 @@
521748 /**
522749 * tegra_soctherm_set_hwtrips() - set HW trip point from DT data
523750 * @dev: struct device * of the SOC_THERM instance
751
+ * @sg: pointer to the sensor group to set the thermtrip temperature for
752
+ * @tz: struct thermal_zone_device *
524753 *
525754 * Configure the SOC_THERM HW trip points, setting "THERMTRIP"
526
- * "THROTTLE" trip points , using "critical" or "hot" type trip_temp
755
+ * "THROTTLE" trip points , using "thermtrips", "critical" or "hot"
756
+ * type trip_temp
527757 * from thermal zone.
528758 * After they have been configured, THERMTRIP or THROTTLE will take
529759 * action when the configured SoC thermal sensor group reaches a
....@@ -545,36 +775,31 @@
545775 {
546776 struct tegra_soctherm *ts = dev_get_drvdata(dev);
547777 struct soctherm_throt_cfg *stc;
548
- int i, trip, temperature;
549
- int ret;
778
+ int i, trip, temperature, ret;
550779
551
- ret = tz->ops->get_crit_temp(tz, &temperature);
552
- if (ret) {
553
- dev_warn(dev, "thermtrip: %s: missing critical temperature\n",
554
- sg->name);
555
- goto set_throttle;
556
- }
780
+ /* Get thermtrips. If missing, try to get critical trips. */
781
+ temperature = tsensor_group_thermtrip_get(ts, sg->id);
782
+ if (min_low_temp == temperature)
783
+ if (tz->ops->get_crit_temp(tz, &temperature))
784
+ temperature = max_high_temp;
557785
558786 ret = thermtrip_program(dev, sg, temperature);
559787 if (ret) {
560
- dev_err(dev, "thermtrip: %s: error during enable\n",
561
- sg->name);
788
+ dev_err(dev, "thermtrip: %s: error during enable\n", sg->name);
562789 return ret;
563790 }
564791
565
- dev_info(dev,
566
- "thermtrip: will shut down when %s reaches %d mC\n",
792
+ dev_info(dev, "thermtrip: will shut down when %s reaches %d mC\n",
567793 sg->name, temperature);
568794
569
-set_throttle:
570795 ret = get_hot_temp(tz, &trip, &temperature);
571796 if (ret) {
572
- dev_warn(dev, "throttrip: %s: missing hot temperature\n",
797
+ dev_info(dev, "throttrip: %s: missing hot temperature\n",
573798 sg->name);
574799 return 0;
575800 }
576801
577
- for (i = 0; i < THROTTLE_SIZE; i++) {
802
+ for (i = 0; i < THROTTLE_OC1; i++) {
578803 struct thermal_cooling_device *cdev;
579804
580805 if (!ts->throt_cfgs[i].init)
....@@ -600,9 +825,466 @@
600825 }
601826
602827 if (i == THROTTLE_SIZE)
603
- dev_warn(dev, "throttrip: %s: missing throttle cdev\n",
828
+ dev_info(dev, "throttrip: %s: missing throttle cdev\n",
604829 sg->name);
605830
831
+ return 0;
832
+}
833
+
834
+static irqreturn_t soctherm_thermal_isr(int irq, void *dev_id)
835
+{
836
+ struct tegra_soctherm *ts = dev_id;
837
+ u32 r;
838
+
839
+ /* Case for no lock:
840
+ * Although interrupts are enabled in set_trips, there is still no need
841
+ * to lock here because the interrupts are disabled before programming
842
+ * new trip points. Hence there cant be a interrupt on the same sensor.
843
+ * An interrupt can however occur on a sensor while trips are being
844
+ * programmed on a different one. This beign a LEVEL interrupt won't
845
+ * cause a new interrupt but this is taken care of by the re-reading of
846
+ * the STATUS register in the thread function.
847
+ */
848
+ r = readl(ts->regs + THERMCTL_INTR_STATUS);
849
+ writel(r, ts->regs + THERMCTL_INTR_DISABLE);
850
+
851
+ return IRQ_WAKE_THREAD;
852
+}
853
+
854
+/**
855
+ * soctherm_thermal_isr_thread() - Handles a thermal interrupt request
856
+ * @irq: The interrupt number being requested; not used
857
+ * @dev_id: Opaque pointer to tegra_soctherm;
858
+ *
859
+ * Clears the interrupt status register if there are expected
860
+ * interrupt bits set.
861
+ * The interrupt(s) are then handled by updating the corresponding
862
+ * thermal zones.
863
+ *
864
+ * An error is logged if any unexpected interrupt bits are set.
865
+ *
866
+ * Disabled interrupts are re-enabled.
867
+ *
868
+ * Return: %IRQ_HANDLED. Interrupt was handled and no further processing
869
+ * is needed.
870
+ */
871
+static irqreturn_t soctherm_thermal_isr_thread(int irq, void *dev_id)
872
+{
873
+ struct tegra_soctherm *ts = dev_id;
874
+ struct thermal_zone_device *tz;
875
+ u32 st, ex = 0, cp = 0, gp = 0, pl = 0, me = 0;
876
+
877
+ st = readl(ts->regs + THERMCTL_INTR_STATUS);
878
+
879
+ /* deliberately clear expected interrupts handled in SW */
880
+ cp |= st & TH_INTR_CD0_MASK;
881
+ cp |= st & TH_INTR_CU0_MASK;
882
+
883
+ gp |= st & TH_INTR_GD0_MASK;
884
+ gp |= st & TH_INTR_GU0_MASK;
885
+
886
+ pl |= st & TH_INTR_PD0_MASK;
887
+ pl |= st & TH_INTR_PU0_MASK;
888
+
889
+ me |= st & TH_INTR_MD0_MASK;
890
+ me |= st & TH_INTR_MU0_MASK;
891
+
892
+ ex |= cp | gp | pl | me;
893
+ if (ex) {
894
+ writel(ex, ts->regs + THERMCTL_INTR_STATUS);
895
+ st &= ~ex;
896
+
897
+ if (cp) {
898
+ tz = ts->thermctl_tzs[TEGRA124_SOCTHERM_SENSOR_CPU];
899
+ thermal_zone_device_update(tz,
900
+ THERMAL_EVENT_UNSPECIFIED);
901
+ }
902
+
903
+ if (gp) {
904
+ tz = ts->thermctl_tzs[TEGRA124_SOCTHERM_SENSOR_GPU];
905
+ thermal_zone_device_update(tz,
906
+ THERMAL_EVENT_UNSPECIFIED);
907
+ }
908
+
909
+ if (pl) {
910
+ tz = ts->thermctl_tzs[TEGRA124_SOCTHERM_SENSOR_PLLX];
911
+ thermal_zone_device_update(tz,
912
+ THERMAL_EVENT_UNSPECIFIED);
913
+ }
914
+
915
+ if (me) {
916
+ tz = ts->thermctl_tzs[TEGRA124_SOCTHERM_SENSOR_MEM];
917
+ thermal_zone_device_update(tz,
918
+ THERMAL_EVENT_UNSPECIFIED);
919
+ }
920
+ }
921
+
922
+ /* deliberately ignore expected interrupts NOT handled in SW */
923
+ ex |= TH_INTR_IGNORE_MASK;
924
+ st &= ~ex;
925
+
926
+ if (st) {
927
+ /* Whine about any other unexpected INTR bits still set */
928
+ pr_err("soctherm: Ignored unexpected INTRs 0x%08x\n", st);
929
+ writel(st, ts->regs + THERMCTL_INTR_STATUS);
930
+ }
931
+
932
+ return IRQ_HANDLED;
933
+}
934
+
935
+/**
936
+ * soctherm_oc_intr_enable() - Enables the soctherm over-current interrupt
937
+ * @ts: pointer to a struct tegra_soctherm
938
+ * @alarm: The soctherm throttle id
939
+ * @enable: Flag indicating enable the soctherm over-current
940
+ * interrupt or disable it
941
+ *
942
+ * Enables a specific over-current pins @alarm to raise an interrupt if the flag
943
+ * is set and the alarm corresponds to OC1, OC2, OC3, or OC4.
944
+ */
945
+static void soctherm_oc_intr_enable(struct tegra_soctherm *ts,
946
+ enum soctherm_throttle_id alarm,
947
+ bool enable)
948
+{
949
+ u32 r;
950
+
951
+ if (!enable)
952
+ return;
953
+
954
+ r = readl(ts->regs + OC_INTR_ENABLE);
955
+ switch (alarm) {
956
+ case THROTTLE_OC1:
957
+ r = REG_SET_MASK(r, OC_INTR_OC1_MASK, 1);
958
+ break;
959
+ case THROTTLE_OC2:
960
+ r = REG_SET_MASK(r, OC_INTR_OC2_MASK, 1);
961
+ break;
962
+ case THROTTLE_OC3:
963
+ r = REG_SET_MASK(r, OC_INTR_OC3_MASK, 1);
964
+ break;
965
+ case THROTTLE_OC4:
966
+ r = REG_SET_MASK(r, OC_INTR_OC4_MASK, 1);
967
+ break;
968
+ default:
969
+ r = 0;
970
+ break;
971
+ }
972
+ writel(r, ts->regs + OC_INTR_ENABLE);
973
+}
974
+
975
+/**
976
+ * soctherm_handle_alarm() - Handles soctherm alarms
977
+ * @alarm: The soctherm throttle id
978
+ *
979
+ * "Handles" over-current alarms (OC1, OC2, OC3, and OC4) by printing
980
+ * a warning or informative message.
981
+ *
982
+ * Return: -EINVAL for @alarm = THROTTLE_OC3, otherwise 0 (success).
983
+ */
984
+static int soctherm_handle_alarm(enum soctherm_throttle_id alarm)
985
+{
986
+ int rv = -EINVAL;
987
+
988
+ switch (alarm) {
989
+ case THROTTLE_OC1:
990
+ pr_debug("soctherm: Successfully handled OC1 alarm\n");
991
+ rv = 0;
992
+ break;
993
+
994
+ case THROTTLE_OC2:
995
+ pr_debug("soctherm: Successfully handled OC2 alarm\n");
996
+ rv = 0;
997
+ break;
998
+
999
+ case THROTTLE_OC3:
1000
+ pr_debug("soctherm: Successfully handled OC3 alarm\n");
1001
+ rv = 0;
1002
+ break;
1003
+
1004
+ case THROTTLE_OC4:
1005
+ pr_debug("soctherm: Successfully handled OC4 alarm\n");
1006
+ rv = 0;
1007
+ break;
1008
+
1009
+ default:
1010
+ break;
1011
+ }
1012
+
1013
+ if (rv)
1014
+ pr_err("soctherm: ERROR in handling %s alarm\n",
1015
+ throt_names[alarm]);
1016
+
1017
+ return rv;
1018
+}
1019
+
1020
+/**
1021
+ * soctherm_edp_isr_thread() - log an over-current interrupt request
1022
+ * @irq: OC irq number. Currently not being used. See description
1023
+ * @arg: a void pointer for callback, currently not being used
1024
+ *
1025
+ * Over-current events are handled in hardware. This function is called to log
1026
+ * and handle any OC events that happened. Additionally, it checks every
1027
+ * over-current interrupt registers for registers are set but
1028
+ * was not expected (i.e. any discrepancy in interrupt status) by the function,
1029
+ * the discrepancy will logged.
1030
+ *
1031
+ * Return: %IRQ_HANDLED
1032
+ */
1033
+static irqreturn_t soctherm_edp_isr_thread(int irq, void *arg)
1034
+{
1035
+ struct tegra_soctherm *ts = arg;
1036
+ u32 st, ex, oc1, oc2, oc3, oc4;
1037
+
1038
+ st = readl(ts->regs + OC_INTR_STATUS);
1039
+
1040
+ /* deliberately clear expected interrupts handled in SW */
1041
+ oc1 = st & OC_INTR_OC1_MASK;
1042
+ oc2 = st & OC_INTR_OC2_MASK;
1043
+ oc3 = st & OC_INTR_OC3_MASK;
1044
+ oc4 = st & OC_INTR_OC4_MASK;
1045
+ ex = oc1 | oc2 | oc3 | oc4;
1046
+
1047
+ pr_err("soctherm: OC ALARM 0x%08x\n", ex);
1048
+ if (ex) {
1049
+ writel(st, ts->regs + OC_INTR_STATUS);
1050
+ st &= ~ex;
1051
+
1052
+ if (oc1 && !soctherm_handle_alarm(THROTTLE_OC1))
1053
+ soctherm_oc_intr_enable(ts, THROTTLE_OC1, true);
1054
+
1055
+ if (oc2 && !soctherm_handle_alarm(THROTTLE_OC2))
1056
+ soctherm_oc_intr_enable(ts, THROTTLE_OC2, true);
1057
+
1058
+ if (oc3 && !soctherm_handle_alarm(THROTTLE_OC3))
1059
+ soctherm_oc_intr_enable(ts, THROTTLE_OC3, true);
1060
+
1061
+ if (oc4 && !soctherm_handle_alarm(THROTTLE_OC4))
1062
+ soctherm_oc_intr_enable(ts, THROTTLE_OC4, true);
1063
+
1064
+ if (oc1 && soc_irq_cdata.irq_enable & BIT(0))
1065
+ handle_nested_irq(
1066
+ irq_find_mapping(soc_irq_cdata.domain, 0));
1067
+
1068
+ if (oc2 && soc_irq_cdata.irq_enable & BIT(1))
1069
+ handle_nested_irq(
1070
+ irq_find_mapping(soc_irq_cdata.domain, 1));
1071
+
1072
+ if (oc3 && soc_irq_cdata.irq_enable & BIT(2))
1073
+ handle_nested_irq(
1074
+ irq_find_mapping(soc_irq_cdata.domain, 2));
1075
+
1076
+ if (oc4 && soc_irq_cdata.irq_enable & BIT(3))
1077
+ handle_nested_irq(
1078
+ irq_find_mapping(soc_irq_cdata.domain, 3));
1079
+ }
1080
+
1081
+ if (st) {
1082
+ pr_err("soctherm: Ignored unexpected OC ALARM 0x%08x\n", st);
1083
+ writel(st, ts->regs + OC_INTR_STATUS);
1084
+ }
1085
+
1086
+ return IRQ_HANDLED;
1087
+}
1088
+
1089
+/**
1090
+ * soctherm_edp_isr() - Disables any active interrupts
1091
+ * @irq: The interrupt request number
1092
+ * @arg: Opaque pointer to an argument
1093
+ *
1094
+ * Writes to the OC_INTR_DISABLE register the over current interrupt status,
1095
+ * masking any asserted interrupts. Doing this prevents the same interrupts
1096
+ * from triggering this isr repeatedly. The thread woken by this isr will
1097
+ * handle asserted interrupts and subsequently unmask/re-enable them.
1098
+ *
1099
+ * The OC_INTR_DISABLE register indicates which OC interrupts
1100
+ * have been disabled.
1101
+ *
1102
+ * Return: %IRQ_WAKE_THREAD, handler requests to wake the handler thread
1103
+ */
1104
+static irqreturn_t soctherm_edp_isr(int irq, void *arg)
1105
+{
1106
+ struct tegra_soctherm *ts = arg;
1107
+ u32 r;
1108
+
1109
+ if (!ts)
1110
+ return IRQ_NONE;
1111
+
1112
+ r = readl(ts->regs + OC_INTR_STATUS);
1113
+ writel(r, ts->regs + OC_INTR_DISABLE);
1114
+
1115
+ return IRQ_WAKE_THREAD;
1116
+}
1117
+
1118
+/**
1119
+ * soctherm_oc_irq_lock() - locks the over-current interrupt request
1120
+ * @data: Interrupt request data
1121
+ *
1122
+ * Looks up the chip data from @data and locks the mutex associated with
1123
+ * a particular over-current interrupt request.
1124
+ */
1125
+static void soctherm_oc_irq_lock(struct irq_data *data)
1126
+{
1127
+ struct soctherm_oc_irq_chip_data *d = irq_data_get_irq_chip_data(data);
1128
+
1129
+ mutex_lock(&d->irq_lock);
1130
+}
1131
+
1132
+/**
1133
+ * soctherm_oc_irq_sync_unlock() - Unlocks the OC interrupt request
1134
+ * @data: Interrupt request data
1135
+ *
1136
+ * Looks up the interrupt request data @data and unlocks the mutex associated
1137
+ * with a particular over-current interrupt request.
1138
+ */
1139
+static void soctherm_oc_irq_sync_unlock(struct irq_data *data)
1140
+{
1141
+ struct soctherm_oc_irq_chip_data *d = irq_data_get_irq_chip_data(data);
1142
+
1143
+ mutex_unlock(&d->irq_lock);
1144
+}
1145
+
1146
+/**
1147
+ * soctherm_oc_irq_enable() - Enables the SOC_THERM over-current interrupt queue
1148
+ * @data: irq_data structure of the chip
1149
+ *
1150
+ * Sets the irq_enable bit of SOC_THERM allowing SOC_THERM
1151
+ * to respond to over-current interrupts.
1152
+ *
1153
+ */
1154
+static void soctherm_oc_irq_enable(struct irq_data *data)
1155
+{
1156
+ struct soctherm_oc_irq_chip_data *d = irq_data_get_irq_chip_data(data);
1157
+
1158
+ d->irq_enable |= BIT(data->hwirq);
1159
+}
1160
+
1161
+/**
1162
+ * soctherm_oc_irq_disable() - Disables overcurrent interrupt requests
1163
+ * @data: The interrupt request information
1164
+ *
1165
+ * Clears the interrupt request enable bit of the overcurrent
1166
+ * interrupt request chip data.
1167
+ *
1168
+ * Return: Nothing is returned (void)
1169
+ */
1170
+static void soctherm_oc_irq_disable(struct irq_data *data)
1171
+{
1172
+ struct soctherm_oc_irq_chip_data *d = irq_data_get_irq_chip_data(data);
1173
+
1174
+ d->irq_enable &= ~BIT(data->hwirq);
1175
+}
1176
+
1177
+static int soctherm_oc_irq_set_type(struct irq_data *data, unsigned int type)
1178
+{
1179
+ return 0;
1180
+}
1181
+
1182
+/**
1183
+ * soctherm_oc_irq_map() - SOC_THERM interrupt request domain mapper
1184
+ * @h: Interrupt request domain
1185
+ * @virq: Virtual interrupt request number
1186
+ * @hw: Hardware interrupt request number
1187
+ *
1188
+ * Mapping callback function for SOC_THERM's irq_domain. When a SOC_THERM
1189
+ * interrupt request is called, the irq_domain takes the request's virtual
1190
+ * request number (much like a virtual memory address) and maps it to a
1191
+ * physical hardware request number.
1192
+ *
1193
+ * When a mapping doesn't already exist for a virtual request number, the
1194
+ * irq_domain calls this function to associate the virtual request number with
1195
+ * a hardware request number.
1196
+ *
1197
+ * Return: 0
1198
+ */
1199
+static int soctherm_oc_irq_map(struct irq_domain *h, unsigned int virq,
1200
+ irq_hw_number_t hw)
1201
+{
1202
+ struct soctherm_oc_irq_chip_data *data = h->host_data;
1203
+
1204
+ irq_set_chip_data(virq, data);
1205
+ irq_set_chip(virq, &data->irq_chip);
1206
+ irq_set_nested_thread(virq, 1);
1207
+ return 0;
1208
+}
1209
+
1210
+/**
1211
+ * soctherm_irq_domain_xlate_twocell() - xlate for soctherm interrupts
1212
+ * @d: Interrupt request domain
1213
+ * @ctrlr: Controller device tree node
1214
+ * @intspec: Array of u32s from DTs "interrupt" property
1215
+ * @intsize: Number of values inside the intspec array
1216
+ * @out_hwirq: HW IRQ value associated with this interrupt
1217
+ * @out_type: The IRQ SENSE type for this interrupt.
1218
+ *
1219
+ * This Device Tree IRQ specifier translation function will translate a
1220
+ * specific "interrupt" as defined by 2 DT values where the cell values map
1221
+ * the hwirq number + 1 and linux irq flags. Since the output is the hwirq
1222
+ * number, this function will subtract 1 from the value listed in DT.
1223
+ *
1224
+ * Return: 0
1225
+ */
1226
+static int soctherm_irq_domain_xlate_twocell(struct irq_domain *d,
1227
+ struct device_node *ctrlr, const u32 *intspec, unsigned int intsize,
1228
+ irq_hw_number_t *out_hwirq, unsigned int *out_type)
1229
+{
1230
+ if (WARN_ON(intsize < 2))
1231
+ return -EINVAL;
1232
+
1233
+ /*
1234
+ * The HW value is 1 index less than the DT IRQ values.
1235
+ * i.e. OC4 goes to HW index 3.
1236
+ */
1237
+ *out_hwirq = intspec[0] - 1;
1238
+ *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK;
1239
+ return 0;
1240
+}
1241
+
1242
+static const struct irq_domain_ops soctherm_oc_domain_ops = {
1243
+ .map = soctherm_oc_irq_map,
1244
+ .xlate = soctherm_irq_domain_xlate_twocell,
1245
+};
1246
+
1247
+/**
1248
+ * soctherm_oc_int_init() - Initial enabling of the over
1249
+ * current interrupts
1250
+ * @np: The devicetree node for soctherm
1251
+ * @num_irqs: The number of new interrupt requests
1252
+ *
1253
+ * Sets the over current interrupt request chip data
1254
+ *
1255
+ * Return: 0 on success or if overcurrent interrupts are not enabled,
1256
+ * -ENOMEM (out of memory), or irq_base if the function failed to
1257
+ * allocate the irqs
1258
+ */
1259
+static int soctherm_oc_int_init(struct device_node *np, int num_irqs)
1260
+{
1261
+ if (!num_irqs) {
1262
+ pr_info("%s(): OC interrupts are not enabled\n", __func__);
1263
+ return 0;
1264
+ }
1265
+
1266
+ mutex_init(&soc_irq_cdata.irq_lock);
1267
+ soc_irq_cdata.irq_enable = 0;
1268
+
1269
+ soc_irq_cdata.irq_chip.name = "soc_therm_oc";
1270
+ soc_irq_cdata.irq_chip.irq_bus_lock = soctherm_oc_irq_lock;
1271
+ soc_irq_cdata.irq_chip.irq_bus_sync_unlock =
1272
+ soctherm_oc_irq_sync_unlock;
1273
+ soc_irq_cdata.irq_chip.irq_disable = soctherm_oc_irq_disable;
1274
+ soc_irq_cdata.irq_chip.irq_enable = soctherm_oc_irq_enable;
1275
+ soc_irq_cdata.irq_chip.irq_set_type = soctherm_oc_irq_set_type;
1276
+ soc_irq_cdata.irq_chip.irq_set_wake = NULL;
1277
+
1278
+ soc_irq_cdata.domain = irq_domain_add_linear(np, num_irqs,
1279
+ &soctherm_oc_domain_ops,
1280
+ &soc_irq_cdata);
1281
+
1282
+ if (!soc_irq_cdata.domain) {
1283
+ pr_err("%s: Failed to create IRQ domain\n", __func__);
1284
+ return -ENOMEM;
1285
+ }
1286
+
1287
+ pr_debug("%s(): OC interrupts enabled successful\n", __func__);
6061288 return 0;
6071289 }
6081290
....@@ -803,38 +1485,18 @@
8031485 return 0;
8041486 }
8051487
806
-static int regs_open(struct inode *inode, struct file *file)
807
-{
808
- return single_open(file, regs_show, inode->i_private);
809
-}
810
-
811
-static const struct file_operations regs_fops = {
812
- .open = regs_open,
813
- .read = seq_read,
814
- .llseek = seq_lseek,
815
- .release = single_release,
816
-};
1488
+DEFINE_SHOW_ATTRIBUTE(regs);
8171489
8181490 static void soctherm_debug_init(struct platform_device *pdev)
8191491 {
8201492 struct tegra_soctherm *tegra = platform_get_drvdata(pdev);
821
- struct dentry *root, *file;
1493
+ struct dentry *root;
8221494
8231495 root = debugfs_create_dir("soctherm", NULL);
824
- if (!root) {
825
- dev_err(&pdev->dev, "failed to create debugfs directory\n");
826
- return;
827
- }
8281496
8291497 tegra->debugfs_dir = root;
8301498
831
- file = debugfs_create_file("reg_contents", 0644, root,
832
- pdev, &regs_fops);
833
- if (!file) {
834
- dev_err(&pdev->dev, "failed to create debugfs file\n");
835
- debugfs_remove_recursive(tegra->debugfs_dir);
836
- tegra->debugfs_dir = NULL;
837
- }
1499
+ debugfs_create_file("reg_contents", 0644, root, pdev, &regs_fops);
8381500 }
8391501 #else
8401502 static inline void soctherm_debug_init(struct platform_device *pdev) {}
....@@ -907,9 +1569,124 @@
9071569 .set_cur_state = throt_set_cdev_state,
9081570 };
9091571
1572
+static int soctherm_thermtrips_parse(struct platform_device *pdev)
1573
+{
1574
+ struct device *dev = &pdev->dev;
1575
+ struct tegra_soctherm *ts = dev_get_drvdata(dev);
1576
+ struct tsensor_group_thermtrips *tt = ts->soc->thermtrips;
1577
+ const int max_num_prop = ts->soc->num_ttgs * 2;
1578
+ u32 *tlb;
1579
+ int i, j, n, ret;
1580
+
1581
+ if (!tt)
1582
+ return -ENOMEM;
1583
+
1584
+ n = of_property_count_u32_elems(dev->of_node, "nvidia,thermtrips");
1585
+ if (n <= 0) {
1586
+ dev_info(dev,
1587
+ "missing thermtrips, will use critical trips as shut down temp\n");
1588
+ return n;
1589
+ }
1590
+
1591
+ n = min(max_num_prop, n);
1592
+
1593
+ tlb = devm_kcalloc(&pdev->dev, max_num_prop, sizeof(u32), GFP_KERNEL);
1594
+ if (!tlb)
1595
+ return -ENOMEM;
1596
+ ret = of_property_read_u32_array(dev->of_node, "nvidia,thermtrips",
1597
+ tlb, n);
1598
+ if (ret) {
1599
+ dev_err(dev, "invalid num ele: thermtrips:%d\n", ret);
1600
+ return ret;
1601
+ }
1602
+
1603
+ i = 0;
1604
+ for (j = 0; j < n; j = j + 2) {
1605
+ if (tlb[j] >= TEGRA124_SOCTHERM_SENSOR_NUM)
1606
+ continue;
1607
+
1608
+ tt[i].id = tlb[j];
1609
+ tt[i].temp = tlb[j + 1];
1610
+ i++;
1611
+ }
1612
+
1613
+ return 0;
1614
+}
1615
+
1616
+static void soctherm_oc_cfg_parse(struct device *dev,
1617
+ struct device_node *np_oc,
1618
+ struct soctherm_throt_cfg *stc)
1619
+{
1620
+ u32 val;
1621
+
1622
+ if (of_property_read_bool(np_oc, "nvidia,polarity-active-low"))
1623
+ stc->oc_cfg.active_low = 1;
1624
+ else
1625
+ stc->oc_cfg.active_low = 0;
1626
+
1627
+ if (!of_property_read_u32(np_oc, "nvidia,count-threshold", &val)) {
1628
+ stc->oc_cfg.intr_en = 1;
1629
+ stc->oc_cfg.alarm_cnt_thresh = val;
1630
+ }
1631
+
1632
+ if (!of_property_read_u32(np_oc, "nvidia,throttle-period-us", &val))
1633
+ stc->oc_cfg.throt_period = val;
1634
+
1635
+ if (!of_property_read_u32(np_oc, "nvidia,alarm-filter", &val))
1636
+ stc->oc_cfg.alarm_filter = val;
1637
+
1638
+ /* BRIEF throttling by default, do not support STICKY */
1639
+ stc->oc_cfg.mode = OC_THROTTLE_MODE_BRIEF;
1640
+}
1641
+
1642
+static int soctherm_throt_cfg_parse(struct device *dev,
1643
+ struct device_node *np,
1644
+ struct soctherm_throt_cfg *stc)
1645
+{
1646
+ struct tegra_soctherm *ts = dev_get_drvdata(dev);
1647
+ int ret;
1648
+ u32 val;
1649
+
1650
+ ret = of_property_read_u32(np, "nvidia,priority", &val);
1651
+ if (ret) {
1652
+ dev_err(dev, "throttle-cfg: %s: invalid priority\n", stc->name);
1653
+ return -EINVAL;
1654
+ }
1655
+ stc->priority = val;
1656
+
1657
+ ret = of_property_read_u32(np, ts->soc->use_ccroc ?
1658
+ "nvidia,cpu-throt-level" :
1659
+ "nvidia,cpu-throt-percent", &val);
1660
+ if (!ret) {
1661
+ if (ts->soc->use_ccroc &&
1662
+ val <= TEGRA_SOCTHERM_THROT_LEVEL_HIGH)
1663
+ stc->cpu_throt_level = val;
1664
+ else if (!ts->soc->use_ccroc && val <= 100)
1665
+ stc->cpu_throt_depth = val;
1666
+ else
1667
+ goto err;
1668
+ } else {
1669
+ goto err;
1670
+ }
1671
+
1672
+ ret = of_property_read_u32(np, "nvidia,gpu-throt-level", &val);
1673
+ if (!ret && val <= TEGRA_SOCTHERM_THROT_LEVEL_HIGH)
1674
+ stc->gpu_throt_level = val;
1675
+ else
1676
+ goto err;
1677
+
1678
+ return 0;
1679
+
1680
+err:
1681
+ dev_err(dev, "throttle-cfg: %s: no throt prop or invalid prop\n",
1682
+ stc->name);
1683
+ return -EINVAL;
1684
+}
1685
+
9101686 /**
9111687 * soctherm_init_hw_throt_cdev() - Parse the HW throttle configurations
9121688 * and register them as cooling devices.
1689
+ * @pdev: Pointer to platform_device struct
9131690 */
9141691 static void soctherm_init_hw_throt_cdev(struct platform_device *pdev)
9151692 {
....@@ -917,8 +1694,7 @@
9171694 struct tegra_soctherm *ts = dev_get_drvdata(dev);
9181695 struct device_node *np_stc, *np_stcc;
9191696 const char *name;
920
- u32 val;
921
- int i, r;
1697
+ int i;
9221698
9231699 for (i = 0; i < THROTTLE_SIZE; i++) {
9241700 ts->throt_cfgs[i].name = throt_names[i];
....@@ -936,6 +1712,7 @@
9361712 for_each_child_of_node(np_stc, np_stcc) {
9371713 struct soctherm_throt_cfg *stc;
9381714 struct thermal_cooling_device *tcd;
1715
+ int err;
9391716
9401717 name = np_stcc->name;
9411718 stc = find_throttle_cfg_by_name(ts, name);
....@@ -945,51 +1722,34 @@
9451722 continue;
9461723 }
9471724
948
- r = of_property_read_u32(np_stcc, "nvidia,priority", &val);
949
- if (r) {
950
- dev_info(dev,
951
- "throttle-cfg: %s: missing priority\n", name);
1725
+ if (stc->init) {
1726
+ dev_err(dev, "throttle-cfg: %s: redefined!\n", name);
1727
+ of_node_put(np_stcc);
1728
+ break;
1729
+ }
1730
+
1731
+ err = soctherm_throt_cfg_parse(dev, np_stcc, stc);
1732
+ if (err)
9521733 continue;
953
- }
954
- stc->priority = val;
9551734
956
- if (ts->soc->use_ccroc) {
957
- r = of_property_read_u32(np_stcc,
958
- "nvidia,cpu-throt-level",
959
- &val);
960
- if (r) {
961
- dev_info(dev,
962
- "throttle-cfg: %s: missing cpu-throt-level\n",
963
- name);
964
- continue;
965
- }
966
- stc->cpu_throt_level = val;
1735
+ if (stc->id >= THROTTLE_OC1) {
1736
+ soctherm_oc_cfg_parse(dev, np_stcc, stc);
1737
+ stc->init = true;
9671738 } else {
968
- r = of_property_read_u32(np_stcc,
969
- "nvidia,cpu-throt-percent",
970
- &val);
971
- if (r) {
972
- dev_info(dev,
973
- "throttle-cfg: %s: missing cpu-throt-percent\n",
974
- name);
975
- continue;
976
- }
977
- stc->cpu_throt_depth = val;
978
- }
9791739
980
- tcd = thermal_of_cooling_device_register(np_stcc,
1740
+ tcd = thermal_of_cooling_device_register(np_stcc,
9811741 (char *)name, ts,
9821742 &throt_cooling_ops);
983
- of_node_put(np_stcc);
984
- if (IS_ERR_OR_NULL(tcd)) {
985
- dev_err(dev,
986
- "throttle-cfg: %s: failed to register cooling device\n",
987
- name);
988
- continue;
1743
+ if (IS_ERR_OR_NULL(tcd)) {
1744
+ dev_err(dev,
1745
+ "throttle-cfg: %s: failed to register cooling device\n",
1746
+ name);
1747
+ continue;
1748
+ }
1749
+ stc->cdev = tcd;
1750
+ stc->init = true;
9891751 }
9901752
991
- stc->cdev = tcd;
992
- stc->init = true;
9931753 }
9941754
9951755 of_node_put(np_stc);
....@@ -997,6 +1757,7 @@
9971757
9981758 /**
9991759 * throttlectl_cpu_level_cfg() - programs CCROC NV_THERM level config
1760
+ * @ts: pointer to a struct tegra_soctherm
10001761 * @level: describing the level LOW/MED/HIGH of throttling
10011762 *
10021763 * It's necessary to set up the CPU-local CCROC NV_THERM instance with
....@@ -1044,6 +1805,7 @@
10441805
10451806 /**
10461807 * throttlectl_cpu_level_select() - program CPU pulse skipper config
1808
+ * @ts: pointer to a struct tegra_soctherm
10471809 * @throt: the LIGHT/HEAVY of throttle event id
10481810 *
10491811 * Pulse skippers are used to throttle clock frequencies. This
....@@ -1087,6 +1849,7 @@
10871849
10881850 /**
10891851 * throttlectl_cpu_mn() - program CPU pulse skipper configuration
1852
+ * @ts: pointer to a struct tegra_soctherm
10901853 * @throt: the LIGHT/HEAVY of throttle event id
10911854 *
10921855 * Pulse skippers are used to throttle clock frequencies. This
....@@ -1119,7 +1882,53 @@
11191882 }
11201883
11211884 /**
1885
+ * throttlectl_gpu_level_select() - selects throttling level for GPU
1886
+ * @ts: pointer to a struct tegra_soctherm
1887
+ * @throt: the LIGHT/HEAVY of throttle event id
1888
+ *
1889
+ * This function programs soctherm's interface to GK20a NV_THERM to select
1890
+ * pre-configured "Low", "Medium" or "Heavy" throttle levels.
1891
+ *
1892
+ * Return: boolean true if HW was programmed
1893
+ */
1894
+static void throttlectl_gpu_level_select(struct tegra_soctherm *ts,
1895
+ enum soctherm_throttle_id throt)
1896
+{
1897
+ u32 r, level, throt_vect;
1898
+
1899
+ level = ts->throt_cfgs[throt].gpu_throt_level;
1900
+ throt_vect = THROT_LEVEL_TO_DEPTH(level);
1901
+ r = readl(ts->regs + THROT_PSKIP_CTRL(throt, THROTTLE_DEV_GPU));
1902
+ r = REG_SET_MASK(r, THROT_PSKIP_CTRL_ENABLE_MASK, 1);
1903
+ r = REG_SET_MASK(r, THROT_PSKIP_CTRL_VECT_GPU_MASK, throt_vect);
1904
+ writel(r, ts->regs + THROT_PSKIP_CTRL(throt, THROTTLE_DEV_GPU));
1905
+}
1906
+
1907
+static int soctherm_oc_cfg_program(struct tegra_soctherm *ts,
1908
+ enum soctherm_throttle_id throt)
1909
+{
1910
+ u32 r;
1911
+ struct soctherm_oc_cfg *oc = &ts->throt_cfgs[throt].oc_cfg;
1912
+
1913
+ if (oc->mode == OC_THROTTLE_MODE_DISABLED)
1914
+ return -EINVAL;
1915
+
1916
+ r = REG_SET_MASK(0, OC1_CFG_HW_RESTORE_MASK, 1);
1917
+ r = REG_SET_MASK(r, OC1_CFG_THROTTLE_MODE_MASK, oc->mode);
1918
+ r = REG_SET_MASK(r, OC1_CFG_ALARM_POLARITY_MASK, oc->active_low);
1919
+ r = REG_SET_MASK(r, OC1_CFG_EN_THROTTLE_MASK, 1);
1920
+ writel(r, ts->regs + ALARM_CFG(throt));
1921
+ writel(oc->throt_period, ts->regs + ALARM_THROTTLE_PERIOD(throt));
1922
+ writel(oc->alarm_cnt_thresh, ts->regs + ALARM_CNT_THRESHOLD(throt));
1923
+ writel(oc->alarm_filter, ts->regs + ALARM_FILTER(throt));
1924
+ soctherm_oc_intr_enable(ts, throt, oc->intr_en);
1925
+
1926
+ return 0;
1927
+}
1928
+
1929
+/**
11221930 * soctherm_throttle_program() - programs pulse skippers' configuration
1931
+ * @ts: pointer to a struct tegra_soctherm
11231932 * @throt: the LIGHT/HEAVY of the throttle event id.
11241933 *
11251934 * Pulse skippers are used to throttle clock frequencies.
....@@ -1134,11 +1943,16 @@
11341943 if (!stc.init)
11351944 return;
11361945
1946
+ if ((throt >= THROTTLE_OC1) && (soctherm_oc_cfg_program(ts, throt)))
1947
+ return;
1948
+
11371949 /* Setup PSKIP parameters */
11381950 if (ts->soc->use_ccroc)
11391951 throttlectl_cpu_level_select(ts, throt);
11401952 else
11411953 throttlectl_cpu_mn(ts, throt);
1954
+
1955
+ throttlectl_gpu_level_select(ts, throt);
11421956
11431957 r = REG_SET_MASK(0, THROT_PRIORITY_LITE_PRIO_MASK, stc.priority);
11441958 writel(r, ts->regs + THROT_PRIORITY_CTRL(throt));
....@@ -1191,6 +2005,57 @@
11912005 v = STATS_CTL_CLR_DN | STATS_CTL_EN_DN |
11922006 STATS_CTL_CLR_UP | STATS_CTL_EN_UP;
11932007 writel(v, ts->regs + THERMCTL_STATS_CTL);
2008
+}
2009
+
2010
+static int soctherm_interrupts_init(struct platform_device *pdev,
2011
+ struct tegra_soctherm *tegra)
2012
+{
2013
+ struct device_node *np = pdev->dev.of_node;
2014
+ int ret;
2015
+
2016
+ ret = soctherm_oc_int_init(np, TEGRA_SOC_OC_IRQ_MAX);
2017
+ if (ret < 0) {
2018
+ dev_err(&pdev->dev, "soctherm_oc_int_init failed\n");
2019
+ return ret;
2020
+ }
2021
+
2022
+ tegra->thermal_irq = platform_get_irq(pdev, 0);
2023
+ if (tegra->thermal_irq < 0) {
2024
+ dev_dbg(&pdev->dev, "get 'thermal_irq' failed.\n");
2025
+ return 0;
2026
+ }
2027
+
2028
+ tegra->edp_irq = platform_get_irq(pdev, 1);
2029
+ if (tegra->edp_irq < 0) {
2030
+ dev_dbg(&pdev->dev, "get 'edp_irq' failed.\n");
2031
+ return 0;
2032
+ }
2033
+
2034
+ ret = devm_request_threaded_irq(&pdev->dev,
2035
+ tegra->thermal_irq,
2036
+ soctherm_thermal_isr,
2037
+ soctherm_thermal_isr_thread,
2038
+ IRQF_ONESHOT,
2039
+ dev_name(&pdev->dev),
2040
+ tegra);
2041
+ if (ret < 0) {
2042
+ dev_err(&pdev->dev, "request_irq 'thermal_irq' failed.\n");
2043
+ return ret;
2044
+ }
2045
+
2046
+ ret = devm_request_threaded_irq(&pdev->dev,
2047
+ tegra->edp_irq,
2048
+ soctherm_edp_isr,
2049
+ soctherm_edp_isr_thread,
2050
+ IRQF_ONESHOT,
2051
+ "soctherm_edp",
2052
+ tegra);
2053
+ if (ret < 0) {
2054
+ dev_err(&pdev->dev, "request_irq 'edp_irq' failed.\n");
2055
+ return ret;
2056
+ }
2057
+
2058
+ return 0;
11942059 }
11952060
11962061 static void soctherm_init(struct platform_device *pdev)
....@@ -1270,6 +2135,7 @@
12702135 if (!tegra)
12712136 return -ENOMEM;
12722137
2138
+ mutex_init(&tegra->thermctl_lock);
12732139 dev_set_drvdata(&pdev->dev, tegra);
12742140
12752141 tegra->soc = soc;
....@@ -1339,7 +2205,7 @@
13392205 }
13402206
13412207 tegra->thermctl_tzs = devm_kcalloc(&pdev->dev,
1342
- soc->num_ttgs, sizeof(*z),
2208
+ soc->num_ttgs, sizeof(z),
13432209 GFP_KERNEL);
13442210 if (!tegra->thermctl_tzs)
13452211 return -ENOMEM;
....@@ -1347,6 +2213,8 @@
13472213 err = soctherm_clk_enable(pdev, true);
13482214 if (err)
13492215 return err;
2216
+
2217
+ soctherm_thermtrips_parse(pdev);
13502218
13512219 soctherm_init_hw_throt_cdev(pdev);
13522220
....@@ -1384,6 +2252,8 @@
13842252 goto disable_clocks;
13852253 }
13862254
2255
+ err = soctherm_interrupts_init(pdev, tegra);
2256
+
13872257 soctherm_debug_init(pdev);
13882258
13892259 return 0;