2284 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (c) 2014 - 2018, NVIDIA CORPORATION. All rights reserved.4 *5 * Author:6 * Mikko Perttunen <mperttunen@nvidia.com>7 *8 * This software is licensed under the terms of the GNU General Public9 * License version 2, as published by the Free Software Foundation, and10 * may be copied, distributed, and modified under those terms.11 *12 * This program is distributed in the hope that it will be useful,13 * but WITHOUT ANY WARRANTY; without even the implied warranty of14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the15 * GNU General Public License for more details.16 *17 */18 19#include <linux/debugfs.h>20#include <linux/bitops.h>21#include <linux/clk.h>22#include <linux/delay.h>23#include <linux/err.h>24#include <linux/interrupt.h>25#include <linux/io.h>26#include <linux/irq.h>27#include <linux/irqdomain.h>28#include <linux/module.h>29#include <linux/of.h>30#include <linux/platform_device.h>31#include <linux/reset.h>32#include <linux/thermal.h>33 34#include <dt-bindings/thermal/tegra124-soctherm.h>35 36#include "../thermal_core.h"37#include "soctherm.h"38 39#define SENSOR_CONFIG0 040#define SENSOR_CONFIG0_STOP BIT(0)41#define SENSOR_CONFIG0_CPTR_OVER BIT(2)42#define SENSOR_CONFIG0_OVER BIT(3)43#define SENSOR_CONFIG0_TCALC_OVER BIT(4)44#define SENSOR_CONFIG0_TALL_MASK (0xfffff << 8)45#define SENSOR_CONFIG0_TALL_SHIFT 846 47#define SENSOR_CONFIG1 448#define SENSOR_CONFIG1_TSAMPLE_MASK 0x3ff49#define SENSOR_CONFIG1_TSAMPLE_SHIFT 050#define SENSOR_CONFIG1_TIDDQ_EN_MASK (0x3f << 15)51#define SENSOR_CONFIG1_TIDDQ_EN_SHIFT 1552#define SENSOR_CONFIG1_TEN_COUNT_MASK (0x3f << 24)53#define SENSOR_CONFIG1_TEN_COUNT_SHIFT 2454#define SENSOR_CONFIG1_TEMP_ENABLE BIT(31)55 56/*57 * SENSOR_CONFIG2 is defined in soctherm.h58 * because, it will be used by tegra_soctherm_fuse.c59 */60 61#define SENSOR_STATUS0 0xc62#define SENSOR_STATUS0_VALID_MASK BIT(31)63#define SENSOR_STATUS0_CAPTURE_MASK 0xffff64 65#define SENSOR_STATUS1 0x1066#define SENSOR_STATUS1_TEMP_VALID_MASK BIT(31)67#define SENSOR_STATUS1_TEMP_MASK 0xffff68 69#define READBACK_VALUE_MASK 0xff0070#define READBACK_VALUE_SHIFT 871#define READBACK_ADD_HALF BIT(7)72#define READBACK_NEGATE BIT(0)73 74/*75 * THERMCTL_LEVEL0_GROUP_CPU is defined in soctherm.h76 * because it will be used by tegraxxx_soctherm.c77 */78#define THERMCTL_LVL0_CPU0_EN_MASK BIT(8)79#define THERMCTL_LVL0_CPU0_CPU_THROT_MASK (0x3 << 5)80#define THERMCTL_LVL0_CPU0_CPU_THROT_LIGHT 0x181#define THERMCTL_LVL0_CPU0_CPU_THROT_HEAVY 0x282#define THERMCTL_LVL0_CPU0_GPU_THROT_MASK (0x3 << 3)83#define THERMCTL_LVL0_CPU0_GPU_THROT_LIGHT 0x184#define THERMCTL_LVL0_CPU0_GPU_THROT_HEAVY 0x285#define THERMCTL_LVL0_CPU0_MEM_THROT_MASK BIT(2)86#define THERMCTL_LVL0_CPU0_STATUS_MASK 0x387 88#define THERMCTL_LVL0_UP_STATS 0x1089#define THERMCTL_LVL0_DN_STATS 0x1490 91#define THERMCTL_INTR_STATUS 0x8492 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 0xFCFCFCFC102 103#define THERMCTL_STATS_CTL 0x94104#define STATS_CTL_CLR_DN 0x8105#define STATS_CTL_EN_DN 0x4106#define STATS_CTL_CLR_UP 0x2107#define STATS_CTL_EN_UP 0x1108 109#define OC1_CFG 0x310110#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 0x314118#define OC1_THROTTLE_PERIOD 0x318119#define OC1_ALARM_COUNT 0x31c120#define OC1_FILTER 0x320121#define OC1_STATS 0x3a8122 123#define OC_INTR_STATUS 0x39c124#define OC_INTR_ENABLE 0x3a0125#define OC_INTR_DISABLE 0x3a4126#define OC_STATS_CTL 0x3c4127#define OC_STATS_CTL_CLR_ALL 0x2128#define OC_STATS_CTL_EN_ALL 0x1129 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)135 136#define THROT_GLOBAL_CFG 0x400137#define THROT_GLOBAL_ENB_MASK BIT(0)138 139#define CPU_PSKIP_STATUS 0x418140#define XPU_PSKIP_STATUS_M_MASK (0xff << 12)141#define XPU_PSKIP_STATUS_N_MASK (0xff << 4)142#define XPU_PSKIP_STATUS_SW_OVERRIDE_MASK BIT(1)143#define XPU_PSKIP_STATUS_ENABLED_MASK BIT(0)144 145#define THROT_PRIORITY_LOCK 0x424146#define THROT_PRIORITY_LOCK_PRIORITY_MASK 0xff147 148#define THROT_STATUS 0x428149#define THROT_STATUS_BREACH_MASK BIT(12)150#define THROT_STATUS_STATE_MASK (0xff << 4)151#define THROT_STATUS_ENABLED_MASK BIT(0)152 153#define THROT_PSKIP_CTRL_LITE_CPU 0x430154#define THROT_PSKIP_CTRL_ENABLE_MASK BIT(31)155#define THROT_PSKIP_CTRL_DIVIDEND_MASK (0xff << 8)156#define THROT_PSKIP_CTRL_DIVISOR_MASK 0xff157#define THROT_PSKIP_CTRL_VECT_GPU_MASK (0x7 << 16)158#define THROT_PSKIP_CTRL_VECT_CPU_MASK (0x7 << 8)159#define THROT_PSKIP_CTRL_VECT2_CPU_MASK 0x7160 161#define THROT_VECT_NONE 0x0 /* 3'b000 */162#define THROT_VECT_LOW 0x1 /* 3'b001 */163#define THROT_VECT_MED 0x3 /* 3'b011 */164#define THROT_VECT_HIGH 0x7 /* 3'b111 */165 166#define THROT_PSKIP_RAMP_LITE_CPU 0x434167#define THROT_PSKIP_RAMP_SEQ_BYPASS_MODE_MASK BIT(31)168#define THROT_PSKIP_RAMP_DURATION_MASK (0xffff << 8)169#define THROT_PSKIP_RAMP_STEP_MASK 0xff170 171#define THROT_PRIORITY_LITE 0x444172#define THROT_PRIORITY_LITE_PRIO_MASK 0xff173 174#define THROT_DELAY_LITE 0x448175#define THROT_DELAY_LITE_DELAY_MASK 0xff176 177/* car register offsets needed for enabling HW throttling */178#define CAR_SUPER_CCLKG_DIVIDER 0x36c179#define CDIVG_USE_THERM_CONTROLS_MASK BIT(30)180 181/* ccroc register offsets needed for enabling HW throttling for Tegra132 */182#define CCROC_SUPER_CCLKG_DIVIDER 0x024183 184#define CCROC_GLOBAL_CFG 0x148185 186#define CCROC_THROT_PSKIP_RAMP_CPU 0x150187#define CCROC_THROT_PSKIP_RAMP_SEQ_BYPASS_MODE_MASK BIT(31)188#define CCROC_THROT_PSKIP_RAMP_DURATION_MASK (0xffff << 8)189#define CCROC_THROT_PSKIP_RAMP_STEP_MASK 0xff190 191#define CCROC_THROT_PSKIP_CTRL_CPU 0x154192#define CCROC_THROT_PSKIP_CTRL_ENB_MASK BIT(31)193#define CCROC_THROT_PSKIP_CTRL_DIVIDEND_MASK (0xff << 8)194#define CCROC_THROT_PSKIP_CTRL_DIVISOR_MASK 0xff195 196/* get val from register(r) mask bits(m) */197#define REG_GET_MASK(r, m) (((r) & (m)) >> (ffs(m) - 1))198/* set val(v) to mask bits(m) of register(r) */199#define REG_SET_MASK(r, m, v) (((r) & ~(m)) | \200 (((v) & (m >> (ffs(m) - 1))) << (ffs(m) - 1)))201 202/* get dividend from the depth */203#define THROT_DEPTH_DIVIDEND(depth) ((256 * (100 - (depth)) / 100) - 1)204 205/* gk20a nv_therm interface N:3 Mapping. Levels defined in tegra124-soctherm.h206 * level vector207 * NONE 3'b000208 * LOW 3'b001209 * MED 3'b011210 * HIGH 3'b111211 */212#define THROT_LEVEL_TO_DEPTH(level) ((0x1 << (level)) - 1)213 214/* get THROT_PSKIP_xxx offset per LIGHT/HEAVY throt and CPU/GPU dev */215#define THROT_OFFSET 0x30216#define THROT_PSKIP_CTRL(throt, dev) (THROT_PSKIP_CTRL_LITE_CPU + \217 (THROT_OFFSET * throt) + (8 * dev))218#define THROT_PSKIP_RAMP(throt, dev) (THROT_PSKIP_RAMP_LITE_CPU + \219 (THROT_OFFSET * throt) + (8 * dev))220 221/* get THROT_xxx_CTRL offset per LIGHT/HEAVY throt */222#define THROT_PRIORITY_CTRL(throt) (THROT_PRIORITY_LITE + \223 (THROT_OFFSET * throt))224#define THROT_DELAY_CTRL(throt) (THROT_DELAY_LITE + \225 (THROT_OFFSET * throt))226 227#define ALARM_OFFSET 0x14228#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 246/* get CCROC_THROT_PSKIP_xxx offset per HIGH/MED/LOW vect*/247#define CCROC_THROT_OFFSET 0x0c248#define CCROC_THROT_PSKIP_CTRL_CPU_REG(vect) (CCROC_THROT_PSKIP_CTRL_CPU + \249 (CCROC_THROT_OFFSET * vect))250#define CCROC_THROT_PSKIP_RAMP_CPU_REG(vect) (CCROC_THROT_PSKIP_RAMP_CPU + \251 (CCROC_THROT_OFFSET * vect))252 253/* get THERMCTL_LEVELx offset per CPU/GPU/MEM/TSENSE rg and LEVEL0~3 lv */254#define THERMCTL_LVL_REGS_SIZE 0x20255#define THERMCTL_LVL_REG(rg, lv) ((rg) + ((lv) * THERMCTL_LVL_REGS_SIZE))256 257#define OC_THROTTLE_MODE_DISABLED 0258#define OC_THROTTLE_MODE_BRIEF 2259 260static const int min_low_temp = -127000;261static const int max_high_temp = 127000;262 263enum soctherm_throttle_id {264 THROTTLE_LIGHT = 0,265 THROTTLE_HEAVY,266 THROTTLE_OC1,267 THROTTLE_OC2,268 THROTTLE_OC3,269 THROTTLE_OC4,270 THROTTLE_OC5, /* OC5 is reserved */271 THROTTLE_SIZE,272};273 274enum 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,281};282 283enum soctherm_throttle_dev_id {284 THROTTLE_DEV_CPU = 0,285 THROTTLE_DEV_GPU,286 THROTTLE_DEV_SIZE,287};288 289static const char *const throt_names[] = {290 [THROTTLE_LIGHT] = "light",291 [THROTTLE_HEAVY] = "heavy",292 [THROTTLE_OC1] = "oc1",293 [THROTTLE_OC2] = "oc2",294 [THROTTLE_OC3] = "oc3",295 [THROTTLE_OC4] = "oc4",296 [THROTTLE_OC5] = "oc5",297};298 299struct tegra_soctherm;300struct tegra_thermctl_zone {301 void __iomem *reg;302 struct device *dev;303 struct tegra_soctherm *ts;304 struct thermal_zone_device *tz;305 const struct tegra_tsensor_group *sg;306};307 308struct 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 317struct soctherm_throt_cfg {318 const char *name;319 unsigned int id;320 u8 priority;321 u8 cpu_throt_level;322 u32 cpu_throt_depth;323 u32 gpu_throt_level;324 struct soctherm_oc_cfg oc_cfg;325 struct thermal_cooling_device *cdev;326 bool init;327};328 329struct tegra_soctherm {330 struct reset_control *reset;331 struct clk *clock_tsensor;332 struct clk *clock_soctherm;333 void __iomem *regs;334 void __iomem *clk_regs;335 void __iomem *ccroc_regs;336 337 int thermal_irq;338 int edp_irq;339 340 u32 *calib;341 struct thermal_zone_device **thermctl_tzs;342 struct tegra_soctherm_soc *soc;343 344 struct soctherm_throt_cfg throt_cfgs[THROTTLE_SIZE];345 346 struct dentry *debugfs_dir;347 348 struct mutex thermctl_lock;349};350 351struct 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 358static struct soctherm_oc_irq_chip_data soc_irq_cdata;359 360/**361 * ccroc_writel() - writes a value to a CCROC register362 * @ts: pointer to a struct tegra_soctherm363 * @value: the value to write364 * @reg: the register offset365 *366 * Writes @v to @reg. No return value.367 */368static inline void ccroc_writel(struct tegra_soctherm *ts, u32 value, u32 reg)369{370 writel(value, (ts->ccroc_regs + reg));371}372 373/**374 * ccroc_readl() - reads specified register from CCROC IP block375 * @ts: pointer to a struct tegra_soctherm376 * @reg: register address to be read377 *378 * Return: the value of the register379 */380static inline u32 ccroc_readl(struct tegra_soctherm *ts, u32 reg)381{382 return readl(ts->ccroc_regs + reg);383}384 385static void enable_tsensor(struct tegra_soctherm *tegra, unsigned int i)386{387 const struct tegra_tsensor *sensor = &tegra->soc->tsensors[i];388 void __iomem *base = tegra->regs + sensor->base;389 unsigned int val;390 391 val = sensor->config->tall << SENSOR_CONFIG0_TALL_SHIFT;392 writel(val, base + SENSOR_CONFIG0);393 394 val = (sensor->config->tsample - 1) << SENSOR_CONFIG1_TSAMPLE_SHIFT;395 val |= sensor->config->tiddq_en << SENSOR_CONFIG1_TIDDQ_EN_SHIFT;396 val |= sensor->config->ten_count << SENSOR_CONFIG1_TEN_COUNT_SHIFT;397 val |= SENSOR_CONFIG1_TEMP_ENABLE;398 writel(val, base + SENSOR_CONFIG1);399 400 writel(tegra->calib[i], base + SENSOR_CONFIG2);401}402 403/*404 * Translate from soctherm readback format to millicelsius.405 * The soctherm readback format in bits is as follows:406 * TTTTTTTT H______N407 * where T's contain the temperature in Celsius,408 * H denotes an addition of 0.5 Celsius and N denotes negation409 * of the final value.410 */411static int translate_temp(u16 val)412{413 int t;414 415 t = ((val & READBACK_VALUE_MASK) >> READBACK_VALUE_SHIFT) * 1000;416 if (val & READBACK_ADD_HALF)417 t += 500;418 if (val & READBACK_NEGATE)419 t *= -1;420 421 return t;422}423 424static int tegra_thermctl_get_temp(struct thermal_zone_device *tz, int *out_temp)425{426 struct tegra_thermctl_zone *zone = thermal_zone_device_priv(tz);427 u32 val;428 429 val = readl(zone->reg);430 val = REG_GET_MASK(val, zone->sg->sensor_temp_mask);431 *out_temp = translate_temp(val);432 433 return 0;434}435 436/**437 * enforce_temp_range() - check and enforce temperature range [min, max]438 * @dev: struct device * of the SOC_THERM instance439 * @trip_temp: the trip temperature to check440 *441 * Checks and enforces the permitted temperature range that SOC_THERM442 * HW can support This is443 * done while taking care of precision.444 *445 * Return: The precision adjusted capped temperature in millicelsius.446 */447static int enforce_temp_range(struct device *dev, int trip_temp)448{449 int temp;450 451 temp = clamp_val(trip_temp, min_low_temp, max_high_temp);452 if (temp != trip_temp)453 dev_dbg(dev, "soctherm: trip temperature %d forced to %d\n",454 trip_temp, temp);455 return temp;456}457 458/**459 * thermtrip_program() - Configures the hardware to shut down the460 * system if a given sensor group reaches a given temperature461 * @dev: ptr to the struct device for the SOC_THERM IP block462 * @sg: pointer to the sensor group to set the thermtrip temperature for463 * @trip_temp: the temperature in millicelsius to trigger the thermal trip at464 *465 * Sets the thermal trip threshold of the given sensor group to be the466 * @trip_temp. If this threshold is crossed, the hardware will shut467 * down.468 *469 * Note that, although @trip_temp is specified in millicelsius, the470 * hardware is programmed in degrees Celsius.471 *472 * Return: 0 upon success, or %-EINVAL upon failure.473 */474static int thermtrip_program(struct device *dev,475 const struct tegra_tsensor_group *sg,476 int trip_temp)477{478 struct tegra_soctherm *ts = dev_get_drvdata(dev);479 int temp;480 u32 r;481 482 if (!sg || !sg->thermtrip_threshold_mask)483 return -EINVAL;484 485 temp = enforce_temp_range(dev, trip_temp) / ts->soc->thresh_grain;486 487 r = readl(ts->regs + THERMCTL_THERMTRIP_CTL);488 r = REG_SET_MASK(r, sg->thermtrip_threshold_mask, temp);489 r = REG_SET_MASK(r, sg->thermtrip_enable_mask, 1);490 r = REG_SET_MASK(r, sg->thermtrip_any_en_mask, 0);491 writel(r, ts->regs + THERMCTL_THERMTRIP_CTL);492 493 return 0;494}495 496/**497 * throttrip_program() - Configures the hardware to throttle the498 * pulse if a given sensor group reaches a given temperature499 * @dev: ptr to the struct device for the SOC_THERM IP block500 * @sg: pointer to the sensor group to set the thermtrip temperature for501 * @stc: pointer to the throttle need to be triggered502 * @trip_temp: the temperature in millicelsius to trigger the thermal trip at503 *504 * Sets the thermal trip threshold and throttle event of the given sensor505 * group. If this threshold is crossed, the hardware will trigger the506 * throttle.507 *508 * Note that, although @trip_temp is specified in millicelsius, the509 * hardware is programmed in degrees Celsius.510 *511 * Return: 0 upon success, or %-EINVAL upon failure.512 */513static int throttrip_program(struct device *dev,514 const struct tegra_tsensor_group *sg,515 struct soctherm_throt_cfg *stc,516 int trip_temp)517{518 struct tegra_soctherm *ts = dev_get_drvdata(dev);519 int temp, cpu_throt, gpu_throt;520 unsigned int throt;521 u32 r, reg_off;522 523 if (!sg || !stc || !stc->init)524 return -EINVAL;525 526 temp = enforce_temp_range(dev, trip_temp) / ts->soc->thresh_grain;527 528 /* Hardcode LIGHT on LEVEL1 and HEAVY on LEVEL2 */529 throt = stc->id;530 reg_off = THERMCTL_LVL_REG(sg->thermctl_lvl0_offset, throt + 1);531 532 if (throt == THROTTLE_LIGHT) {533 cpu_throt = THERMCTL_LVL0_CPU0_CPU_THROT_LIGHT;534 gpu_throt = THERMCTL_LVL0_CPU0_GPU_THROT_LIGHT;535 } else {536 cpu_throt = THERMCTL_LVL0_CPU0_CPU_THROT_HEAVY;537 gpu_throt = THERMCTL_LVL0_CPU0_GPU_THROT_HEAVY;538 if (throt != THROTTLE_HEAVY)539 dev_warn(dev,540 "invalid throt id %d - assuming HEAVY",541 throt);542 }543 544 r = readl(ts->regs + reg_off);545 r = REG_SET_MASK(r, sg->thermctl_lvl0_up_thresh_mask, temp);546 r = REG_SET_MASK(r, sg->thermctl_lvl0_dn_thresh_mask, temp);547 r = REG_SET_MASK(r, THERMCTL_LVL0_CPU0_CPU_THROT_MASK, cpu_throt);548 r = REG_SET_MASK(r, THERMCTL_LVL0_CPU0_GPU_THROT_MASK, gpu_throt);549 r = REG_SET_MASK(r, THERMCTL_LVL0_CPU0_EN_MASK, 1);550 writel(r, ts->regs + reg_off);551 552 return 0;553}554 555static struct soctherm_throt_cfg *556find_throttle_cfg_by_name(struct tegra_soctherm *ts, const char *name)557{558 unsigned int i;559 560 for (i = 0; ts->throt_cfgs[i].name; i++)561 if (!strcmp(ts->throt_cfgs[i].name, name))562 return &ts->throt_cfgs[i];563 564 return NULL;565}566 567static 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 585static int tegra_thermctl_set_trip_temp(struct thermal_zone_device *tz,586 const struct thermal_trip *trip, int temp)587{588 struct tegra_thermctl_zone *zone = thermal_zone_device_priv(tz);589 struct tegra_soctherm *ts = zone->ts;590 const struct tegra_tsensor_group *sg = zone->sg;591 struct device *dev = zone->dev;592 593 if (!tz)594 return -EINVAL;595 596 if (trip->type == THERMAL_TRIP_CRITICAL) {597 /*598 * If thermtrips property is set in DT,599 * doesn't need to program critical type trip to HW,600 * if not, program critical trip to HW.601 */602 if (min_low_temp == tsensor_group_thermtrip_get(ts, sg->id))603 return thermtrip_program(dev, sg, temp);604 else605 return 0;606 607 } else if (trip->type == THERMAL_TRIP_HOT) {608 int i;609 610 for (i = 0; i < THROTTLE_SIZE; i++) {611 struct thermal_cooling_device *cdev;612 struct soctherm_throt_cfg *stc;613 614 if (!ts->throt_cfgs[i].init)615 continue;616 617 cdev = ts->throt_cfgs[i].cdev;618 if (thermal_trip_is_bound_to_cdev(tz, trip, cdev))619 stc = find_throttle_cfg_by_name(ts, cdev->type);620 else621 continue;622 623 return throttrip_program(dev, sg, stc, temp);624 }625 }626 627 return 0;628}629 630static void thermal_irq_enable(struct tegra_thermctl_zone *zn)631{632 u32 r;633 634 /* multiple zones could be handling and setting trips at once */635 mutex_lock(&zn->ts->thermctl_lock);636 r = readl(zn->ts->regs + THERMCTL_INTR_ENABLE);637 r = REG_SET_MASK(r, zn->sg->thermctl_isr_mask, TH_INTR_UP_DN_EN);638 writel(r, zn->ts->regs + THERMCTL_INTR_ENABLE);639 mutex_unlock(&zn->ts->thermctl_lock);640}641 642static void thermal_irq_disable(struct tegra_thermctl_zone *zn)643{644 u32 r;645 646 /* multiple zones could be handling and setting trips at once */647 mutex_lock(&zn->ts->thermctl_lock);648 r = readl(zn->ts->regs + THERMCTL_INTR_DISABLE);649 r = REG_SET_MASK(r, zn->sg->thermctl_isr_mask, 0);650 writel(r, zn->ts->regs + THERMCTL_INTR_DISABLE);651 mutex_unlock(&zn->ts->thermctl_lock);652}653 654static int tegra_thermctl_set_trips(struct thermal_zone_device *tz, int lo, int hi)655{656 struct tegra_thermctl_zone *zone = thermal_zone_device_priv(tz);657 u32 r;658 659 thermal_irq_disable(zone);660 661 r = readl(zone->ts->regs + zone->sg->thermctl_lvl0_offset);662 r = REG_SET_MASK(r, THERMCTL_LVL0_CPU0_EN_MASK, 0);663 writel(r, zone->ts->regs + zone->sg->thermctl_lvl0_offset);664 665 lo = enforce_temp_range(zone->dev, lo) / zone->ts->soc->thresh_grain;666 hi = enforce_temp_range(zone->dev, hi) / zone->ts->soc->thresh_grain;667 dev_dbg(zone->dev, "%s hi:%d, lo:%d\n", __func__, hi, lo);668 669 r = REG_SET_MASK(r, zone->sg->thermctl_lvl0_up_thresh_mask, hi);670 r = REG_SET_MASK(r, zone->sg->thermctl_lvl0_dn_thresh_mask, lo);671 r = REG_SET_MASK(r, THERMCTL_LVL0_CPU0_EN_MASK, 1);672 writel(r, zone->ts->regs + zone->sg->thermctl_lvl0_offset);673 674 thermal_irq_enable(zone);675 676 return 0;677}678 679static const struct thermal_zone_device_ops tegra_of_thermal_ops = {680 .get_temp = tegra_thermctl_get_temp,681 .set_trip_temp = tegra_thermctl_set_trip_temp,682 .set_trips = tegra_thermctl_set_trips,683};684 685static int get_hot_trip_cb(struct thermal_trip *trip, void *arg)686{687 const struct thermal_trip **trip_ret = arg;688 689 if (trip->type != THERMAL_TRIP_HOT)690 return 0;691 692 *trip_ret = trip;693 /* Return nonzero to terminate the search. */694 return 1;695}696 697static const struct thermal_trip *get_hot_trip(struct thermal_zone_device *tz)698{699 const struct thermal_trip *trip = NULL;700 701 thermal_zone_for_each_trip(tz, get_hot_trip_cb, &trip);702 703 return trip;704}705 706/**707 * tegra_soctherm_set_hwtrips() - set HW trip point from DT data708 * @dev: struct device * of the SOC_THERM instance709 * @sg: pointer to the sensor group to set the thermtrip temperature for710 * @tz: struct thermal_zone_device *711 *712 * Configure the SOC_THERM HW trip points, setting "THERMTRIP"713 * "THROTTLE" trip points , using "thermtrips", "critical" or "hot"714 * type trip_temp715 * from thermal zone.716 * After they have been configured, THERMTRIP or THROTTLE will take717 * action when the configured SoC thermal sensor group reaches a718 * certain temperature.719 *720 * Return: 0 upon success, or a negative error code on failure.721 * "Success" does not mean that trips was enabled; it could also722 * mean that no node was found in DT.723 * THERMTRIP has been enabled successfully when a message similar to724 * this one appears on the serial console:725 * "thermtrip: will shut down when sensor group XXX reaches YYYYYY mC"726 * THROTTLE has been enabled successfully when a message similar to727 * this one appears on the serial console:728 * ""throttrip: will throttle when sensor group XXX reaches YYYYYY mC"729 */730static int tegra_soctherm_set_hwtrips(struct device *dev,731 const struct tegra_tsensor_group *sg,732 struct thermal_zone_device *tz)733{734 struct tegra_soctherm *ts = dev_get_drvdata(dev);735 const struct thermal_trip *hot_trip;736 struct soctherm_throt_cfg *stc;737 int i, temperature, ret;738 739 /* Get thermtrips. If missing, try to get critical trips. */740 temperature = tsensor_group_thermtrip_get(ts, sg->id);741 if (min_low_temp == temperature)742 if (thermal_zone_get_crit_temp(tz, &temperature))743 temperature = max_high_temp;744 745 ret = thermtrip_program(dev, sg, temperature);746 if (ret) {747 dev_err(dev, "thermtrip: %s: error during enable\n", sg->name);748 return ret;749 }750 751 dev_info(dev, "thermtrip: will shut down when %s reaches %d mC\n",752 sg->name, temperature);753 754 hot_trip = get_hot_trip(tz);755 if (!hot_trip) {756 dev_info(dev, "throttrip: %s: missing hot temperature\n",757 sg->name);758 return 0;759 }760 761 for (i = 0; i < THROTTLE_OC1; i++) {762 struct thermal_cooling_device *cdev;763 764 if (!ts->throt_cfgs[i].init)765 continue;766 767 cdev = ts->throt_cfgs[i].cdev;768 if (thermal_trip_is_bound_to_cdev(tz, hot_trip, cdev))769 stc = find_throttle_cfg_by_name(ts, cdev->type);770 else771 continue;772 773 ret = throttrip_program(dev, sg, stc, temperature);774 if (ret) {775 dev_err(dev, "throttrip: %s: error during enable\n",776 sg->name);777 return ret;778 }779 780 dev_info(dev,781 "throttrip: will throttle when %s reaches %d mC\n",782 sg->name, temperature);783 break;784 }785 786 if (i == THROTTLE_SIZE)787 dev_info(dev, "throttrip: %s: missing throttle cdev\n",788 sg->name);789 790 return 0;791}792 793static irqreturn_t soctherm_thermal_isr(int irq, void *dev_id)794{795 struct tegra_soctherm *ts = dev_id;796 u32 r;797 798 /* Case for no lock:799 * Although interrupts are enabled in set_trips, there is still no need800 * to lock here because the interrupts are disabled before programming801 * new trip points. Hence there cant be a interrupt on the same sensor.802 * An interrupt can however occur on a sensor while trips are being803 * programmed on a different one. This beign a LEVEL interrupt won't804 * cause a new interrupt but this is taken care of by the re-reading of805 * the STATUS register in the thread function.806 */807 r = readl(ts->regs + THERMCTL_INTR_STATUS);808 writel(r, ts->regs + THERMCTL_INTR_DISABLE);809 810 return IRQ_WAKE_THREAD;811}812 813/**814 * soctherm_thermal_isr_thread() - Handles a thermal interrupt request815 * @irq: The interrupt number being requested; not used816 * @dev_id: Opaque pointer to tegra_soctherm;817 *818 * Clears the interrupt status register if there are expected819 * interrupt bits set.820 * The interrupt(s) are then handled by updating the corresponding821 * thermal zones.822 *823 * An error is logged if any unexpected interrupt bits are set.824 *825 * Disabled interrupts are re-enabled.826 *827 * Return: %IRQ_HANDLED. Interrupt was handled and no further processing828 * is needed.829 */830static irqreturn_t soctherm_thermal_isr_thread(int irq, void *dev_id)831{832 struct tegra_soctherm *ts = dev_id;833 struct thermal_zone_device *tz;834 u32 st, ex = 0, cp = 0, gp = 0, pl = 0, me = 0;835 836 st = readl(ts->regs + THERMCTL_INTR_STATUS);837 838 /* deliberately clear expected interrupts handled in SW */839 cp |= st & TH_INTR_CD0_MASK;840 cp |= st & TH_INTR_CU0_MASK;841 842 gp |= st & TH_INTR_GD0_MASK;843 gp |= st & TH_INTR_GU0_MASK;844 845 pl |= st & TH_INTR_PD0_MASK;846 pl |= st & TH_INTR_PU0_MASK;847 848 me |= st & TH_INTR_MD0_MASK;849 me |= st & TH_INTR_MU0_MASK;850 851 ex |= cp | gp | pl | me;852 if (ex) {853 writel(ex, ts->regs + THERMCTL_INTR_STATUS);854 st &= ~ex;855 856 if (cp) {857 tz = ts->thermctl_tzs[TEGRA124_SOCTHERM_SENSOR_CPU];858 thermal_zone_device_update(tz,859 THERMAL_EVENT_UNSPECIFIED);860 }861 862 if (gp) {863 tz = ts->thermctl_tzs[TEGRA124_SOCTHERM_SENSOR_GPU];864 thermal_zone_device_update(tz,865 THERMAL_EVENT_UNSPECIFIED);866 }867 868 if (pl) {869 tz = ts->thermctl_tzs[TEGRA124_SOCTHERM_SENSOR_PLLX];870 thermal_zone_device_update(tz,871 THERMAL_EVENT_UNSPECIFIED);872 }873 874 if (me) {875 tz = ts->thermctl_tzs[TEGRA124_SOCTHERM_SENSOR_MEM];876 thermal_zone_device_update(tz,877 THERMAL_EVENT_UNSPECIFIED);878 }879 }880 881 /* deliberately ignore expected interrupts NOT handled in SW */882 ex |= TH_INTR_IGNORE_MASK;883 st &= ~ex;884 885 if (st) {886 /* Whine about any other unexpected INTR bits still set */887 pr_err("soctherm: Ignored unexpected INTRs 0x%08x\n", st);888 writel(st, ts->regs + THERMCTL_INTR_STATUS);889 }890 891 return IRQ_HANDLED;892}893 894/**895 * soctherm_oc_intr_enable() - Enables the soctherm over-current interrupt896 * @ts: pointer to a struct tegra_soctherm897 * @alarm: The soctherm throttle id898 * @enable: Flag indicating enable the soctherm over-current899 * interrupt or disable it900 *901 * Enables a specific over-current pins @alarm to raise an interrupt if the flag902 * is set and the alarm corresponds to OC1, OC2, OC3, or OC4.903 */904static void soctherm_oc_intr_enable(struct tegra_soctherm *ts,905 enum soctherm_throttle_id alarm,906 bool enable)907{908 u32 r;909 910 if (!enable)911 return;912 913 r = readl(ts->regs + OC_INTR_ENABLE);914 switch (alarm) {915 case THROTTLE_OC1:916 r = REG_SET_MASK(r, OC_INTR_OC1_MASK, 1);917 break;918 case THROTTLE_OC2:919 r = REG_SET_MASK(r, OC_INTR_OC2_MASK, 1);920 break;921 case THROTTLE_OC3:922 r = REG_SET_MASK(r, OC_INTR_OC3_MASK, 1);923 break;924 case THROTTLE_OC4:925 r = REG_SET_MASK(r, OC_INTR_OC4_MASK, 1);926 break;927 default:928 r = 0;929 break;930 }931 writel(r, ts->regs + OC_INTR_ENABLE);932}933 934/**935 * soctherm_handle_alarm() - Handles soctherm alarms936 * @alarm: The soctherm throttle id937 *938 * "Handles" over-current alarms (OC1, OC2, OC3, and OC4) by printing939 * a warning or informative message.940 *941 * Return: -EINVAL for @alarm = THROTTLE_OC3, otherwise 0 (success).942 */943static int soctherm_handle_alarm(enum soctherm_throttle_id alarm)944{945 int rv = -EINVAL;946 947 switch (alarm) {948 case THROTTLE_OC1:949 pr_debug("soctherm: Successfully handled OC1 alarm\n");950 rv = 0;951 break;952 953 case THROTTLE_OC2:954 pr_debug("soctherm: Successfully handled OC2 alarm\n");955 rv = 0;956 break;957 958 case THROTTLE_OC3:959 pr_debug("soctherm: Successfully handled OC3 alarm\n");960 rv = 0;961 break;962 963 case THROTTLE_OC4:964 pr_debug("soctherm: Successfully handled OC4 alarm\n");965 rv = 0;966 break;967 968 default:969 break;970 }971 972 if (rv)973 pr_err("soctherm: ERROR in handling %s alarm\n",974 throt_names[alarm]);975 976 return rv;977}978 979/**980 * soctherm_edp_isr_thread() - log an over-current interrupt request981 * @irq: OC irq number. Currently not being used. See description982 * @arg: a void pointer for callback, currently not being used983 *984 * Over-current events are handled in hardware. This function is called to log985 * and handle any OC events that happened. Additionally, it checks every986 * over-current interrupt registers for registers are set but987 * was not expected (i.e. any discrepancy in interrupt status) by the function,988 * the discrepancy will logged.989 *990 * Return: %IRQ_HANDLED991 */992static irqreturn_t soctherm_edp_isr_thread(int irq, void *arg)993{994 struct tegra_soctherm *ts = arg;995 u32 st, ex, oc1, oc2, oc3, oc4;996 997 st = readl(ts->regs + OC_INTR_STATUS);998 999 /* deliberately clear expected interrupts handled in SW */1000 oc1 = st & OC_INTR_OC1_MASK;1001 oc2 = st & OC_INTR_OC2_MASK;1002 oc3 = st & OC_INTR_OC3_MASK;1003 oc4 = st & OC_INTR_OC4_MASK;1004 ex = oc1 | oc2 | oc3 | oc4;1005 1006 pr_err("soctherm: OC ALARM 0x%08x\n", ex);1007 if (ex) {1008 writel(st, ts->regs + OC_INTR_STATUS);1009 st &= ~ex;1010 1011 if (oc1 && !soctherm_handle_alarm(THROTTLE_OC1))1012 soctherm_oc_intr_enable(ts, THROTTLE_OC1, true);1013 1014 if (oc2 && !soctherm_handle_alarm(THROTTLE_OC2))1015 soctherm_oc_intr_enable(ts, THROTTLE_OC2, true);1016 1017 if (oc3 && !soctherm_handle_alarm(THROTTLE_OC3))1018 soctherm_oc_intr_enable(ts, THROTTLE_OC3, true);1019 1020 if (oc4 && !soctherm_handle_alarm(THROTTLE_OC4))1021 soctherm_oc_intr_enable(ts, THROTTLE_OC4, true);1022 1023 if (oc1 && soc_irq_cdata.irq_enable & BIT(0))1024 handle_nested_irq(1025 irq_find_mapping(soc_irq_cdata.domain, 0));1026 1027 if (oc2 && soc_irq_cdata.irq_enable & BIT(1))1028 handle_nested_irq(1029 irq_find_mapping(soc_irq_cdata.domain, 1));1030 1031 if (oc3 && soc_irq_cdata.irq_enable & BIT(2))1032 handle_nested_irq(1033 irq_find_mapping(soc_irq_cdata.domain, 2));1034 1035 if (oc4 && soc_irq_cdata.irq_enable & BIT(3))1036 handle_nested_irq(1037 irq_find_mapping(soc_irq_cdata.domain, 3));1038 }1039 1040 if (st) {1041 pr_err("soctherm: Ignored unexpected OC ALARM 0x%08x\n", st);1042 writel(st, ts->regs + OC_INTR_STATUS);1043 }1044 1045 return IRQ_HANDLED;1046}1047 1048/**1049 * soctherm_edp_isr() - Disables any active interrupts1050 * @irq: The interrupt request number1051 * @arg: Opaque pointer to an argument1052 *1053 * Writes to the OC_INTR_DISABLE register the over current interrupt status,1054 * masking any asserted interrupts. Doing this prevents the same interrupts1055 * from triggering this isr repeatedly. The thread woken by this isr will1056 * handle asserted interrupts and subsequently unmask/re-enable them.1057 *1058 * The OC_INTR_DISABLE register indicates which OC interrupts1059 * have been disabled.1060 *1061 * Return: %IRQ_WAKE_THREAD, handler requests to wake the handler thread1062 */1063static irqreturn_t soctherm_edp_isr(int irq, void *arg)1064{1065 struct tegra_soctherm *ts = arg;1066 u32 r;1067 1068 if (!ts)1069 return IRQ_NONE;1070 1071 r = readl(ts->regs + OC_INTR_STATUS);1072 writel(r, ts->regs + OC_INTR_DISABLE);1073 1074 return IRQ_WAKE_THREAD;1075}1076 1077/**1078 * soctherm_oc_irq_lock() - locks the over-current interrupt request1079 * @data: Interrupt request data1080 *1081 * Looks up the chip data from @data and locks the mutex associated with1082 * a particular over-current interrupt request.1083 */1084static void soctherm_oc_irq_lock(struct irq_data *data)1085{1086 struct soctherm_oc_irq_chip_data *d = irq_data_get_irq_chip_data(data);1087 1088 mutex_lock(&d->irq_lock);1089}1090 1091/**1092 * soctherm_oc_irq_sync_unlock() - Unlocks the OC interrupt request1093 * @data: Interrupt request data1094 *1095 * Looks up the interrupt request data @data and unlocks the mutex associated1096 * with a particular over-current interrupt request.1097 */1098static void soctherm_oc_irq_sync_unlock(struct irq_data *data)1099{1100 struct soctherm_oc_irq_chip_data *d = irq_data_get_irq_chip_data(data);1101 1102 mutex_unlock(&d->irq_lock);1103}1104 1105/**1106 * soctherm_oc_irq_enable() - Enables the SOC_THERM over-current interrupt queue1107 * @data: irq_data structure of the chip1108 *1109 * Sets the irq_enable bit of SOC_THERM allowing SOC_THERM1110 * to respond to over-current interrupts.1111 *1112 */1113static void soctherm_oc_irq_enable(struct irq_data *data)1114{1115 struct soctherm_oc_irq_chip_data *d = irq_data_get_irq_chip_data(data);1116 1117 d->irq_enable |= BIT(data->hwirq);1118}1119 1120/**1121 * soctherm_oc_irq_disable() - Disables overcurrent interrupt requests1122 * @data: The interrupt request information1123 *1124 * Clears the interrupt request enable bit of the overcurrent1125 * interrupt request chip data.1126 *1127 * Return: Nothing is returned (void)1128 */1129static void soctherm_oc_irq_disable(struct irq_data *data)1130{1131 struct soctherm_oc_irq_chip_data *d = irq_data_get_irq_chip_data(data);1132 1133 d->irq_enable &= ~BIT(data->hwirq);1134}1135 1136static int soctherm_oc_irq_set_type(struct irq_data *data, unsigned int type)1137{1138 return 0;1139}1140 1141/**1142 * soctherm_oc_irq_map() - SOC_THERM interrupt request domain mapper1143 * @h: Interrupt request domain1144 * @virq: Virtual interrupt request number1145 * @hw: Hardware interrupt request number1146 *1147 * Mapping callback function for SOC_THERM's irq_domain. When a SOC_THERM1148 * interrupt request is called, the irq_domain takes the request's virtual1149 * request number (much like a virtual memory address) and maps it to a1150 * physical hardware request number.1151 *1152 * When a mapping doesn't already exist for a virtual request number, the1153 * irq_domain calls this function to associate the virtual request number with1154 * a hardware request number.1155 *1156 * Return: 01157 */1158static int soctherm_oc_irq_map(struct irq_domain *h, unsigned int virq,1159 irq_hw_number_t hw)1160{1161 struct soctherm_oc_irq_chip_data *data = h->host_data;1162 1163 irq_set_chip_data(virq, data);1164 irq_set_chip(virq, &data->irq_chip);1165 irq_set_nested_thread(virq, 1);1166 return 0;1167}1168 1169/**1170 * soctherm_irq_domain_xlate_twocell() - xlate for soctherm interrupts1171 * @d: Interrupt request domain1172 * @ctrlr: Controller device tree node1173 * @intspec: Array of u32s from DTs "interrupt" property1174 * @intsize: Number of values inside the intspec array1175 * @out_hwirq: HW IRQ value associated with this interrupt1176 * @out_type: The IRQ SENSE type for this interrupt.1177 *1178 * This Device Tree IRQ specifier translation function will translate a1179 * specific "interrupt" as defined by 2 DT values where the cell values map1180 * the hwirq number + 1 and linux irq flags. Since the output is the hwirq1181 * number, this function will subtract 1 from the value listed in DT.1182 *1183 * Return: 01184 */1185static int soctherm_irq_domain_xlate_twocell(struct irq_domain *d,1186 struct device_node *ctrlr, const u32 *intspec, unsigned int intsize,1187 irq_hw_number_t *out_hwirq, unsigned int *out_type)1188{1189 if (WARN_ON(intsize < 2))1190 return -EINVAL;1191 1192 /*1193 * The HW value is 1 index less than the DT IRQ values.1194 * i.e. OC4 goes to HW index 3.1195 */1196 *out_hwirq = intspec[0] - 1;1197 *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK;1198 return 0;1199}1200 1201static const struct irq_domain_ops soctherm_oc_domain_ops = {1202 .map = soctherm_oc_irq_map,1203 .xlate = soctherm_irq_domain_xlate_twocell,1204};1205 1206/**1207 * soctherm_oc_int_init() - Initial enabling of the over1208 * current interrupts1209 * @np: The devicetree node for soctherm1210 * @num_irqs: The number of new interrupt requests1211 *1212 * Sets the over current interrupt request chip data1213 *1214 * Return: 0 on success or if overcurrent interrupts are not enabled,1215 * -ENOMEM (out of memory), or irq_base if the function failed to1216 * allocate the irqs1217 */1218static int soctherm_oc_int_init(struct device_node *np, int num_irqs)1219{1220 if (!num_irqs) {1221 pr_info("%s(): OC interrupts are not enabled\n", __func__);1222 return 0;1223 }1224 1225 mutex_init(&soc_irq_cdata.irq_lock);1226 soc_irq_cdata.irq_enable = 0;1227 1228 soc_irq_cdata.irq_chip.name = "soc_therm_oc";1229 soc_irq_cdata.irq_chip.irq_bus_lock = soctherm_oc_irq_lock;1230 soc_irq_cdata.irq_chip.irq_bus_sync_unlock =1231 soctherm_oc_irq_sync_unlock;1232 soc_irq_cdata.irq_chip.irq_disable = soctherm_oc_irq_disable;1233 soc_irq_cdata.irq_chip.irq_enable = soctherm_oc_irq_enable;1234 soc_irq_cdata.irq_chip.irq_set_type = soctherm_oc_irq_set_type;1235 soc_irq_cdata.irq_chip.irq_set_wake = NULL;1236 1237 soc_irq_cdata.domain = irq_domain_add_linear(np, num_irqs,1238 &soctherm_oc_domain_ops,1239 &soc_irq_cdata);1240 1241 if (!soc_irq_cdata.domain) {1242 pr_err("%s: Failed to create IRQ domain\n", __func__);1243 return -ENOMEM;1244 }1245 1246 pr_debug("%s(): OC interrupts enabled successful\n", __func__);1247 return 0;1248}1249 1250#ifdef CONFIG_DEBUG_FS1251static int regs_show(struct seq_file *s, void *data)1252{1253 struct platform_device *pdev = s->private;1254 struct tegra_soctherm *ts = platform_get_drvdata(pdev);1255 const struct tegra_tsensor *tsensors = ts->soc->tsensors;1256 const struct tegra_tsensor_group **ttgs = ts->soc->ttgs;1257 u32 r, state;1258 int i, level;1259 1260 seq_puts(s, "-----TSENSE (convert HW)-----\n");1261 1262 for (i = 0; i < ts->soc->num_tsensors; i++) {1263 r = readl(ts->regs + tsensors[i].base + SENSOR_CONFIG1);1264 state = REG_GET_MASK(r, SENSOR_CONFIG1_TEMP_ENABLE);1265 1266 seq_printf(s, "%s: ", tsensors[i].name);1267 seq_printf(s, "En(%d) ", state);1268 1269 if (!state) {1270 seq_puts(s, "\n");1271 continue;1272 }1273 1274 state = REG_GET_MASK(r, SENSOR_CONFIG1_TIDDQ_EN_MASK);1275 seq_printf(s, "tiddq(%d) ", state);1276 state = REG_GET_MASK(r, SENSOR_CONFIG1_TEN_COUNT_MASK);1277 seq_printf(s, "ten_count(%d) ", state);1278 state = REG_GET_MASK(r, SENSOR_CONFIG1_TSAMPLE_MASK);1279 seq_printf(s, "tsample(%d) ", state + 1);1280 1281 r = readl(ts->regs + tsensors[i].base + SENSOR_STATUS1);1282 state = REG_GET_MASK(r, SENSOR_STATUS1_TEMP_VALID_MASK);1283 seq_printf(s, "Temp(%d/", state);1284 state = REG_GET_MASK(r, SENSOR_STATUS1_TEMP_MASK);1285 seq_printf(s, "%d) ", translate_temp(state));1286 1287 r = readl(ts->regs + tsensors[i].base + SENSOR_STATUS0);1288 state = REG_GET_MASK(r, SENSOR_STATUS0_VALID_MASK);1289 seq_printf(s, "Capture(%d/", state);1290 state = REG_GET_MASK(r, SENSOR_STATUS0_CAPTURE_MASK);1291 seq_printf(s, "%d) ", state);1292 1293 r = readl(ts->regs + tsensors[i].base + SENSOR_CONFIG0);1294 state = REG_GET_MASK(r, SENSOR_CONFIG0_STOP);1295 seq_printf(s, "Stop(%d) ", state);1296 state = REG_GET_MASK(r, SENSOR_CONFIG0_TALL_MASK);1297 seq_printf(s, "Tall(%d) ", state);1298 state = REG_GET_MASK(r, SENSOR_CONFIG0_TCALC_OVER);1299 seq_printf(s, "Over(%d/", state);1300 state = REG_GET_MASK(r, SENSOR_CONFIG0_OVER);1301 seq_printf(s, "%d/", state);1302 state = REG_GET_MASK(r, SENSOR_CONFIG0_CPTR_OVER);1303 seq_printf(s, "%d) ", state);1304 1305 r = readl(ts->regs + tsensors[i].base + SENSOR_CONFIG2);1306 state = REG_GET_MASK(r, SENSOR_CONFIG2_THERMA_MASK);1307 seq_printf(s, "Therm_A/B(%d/", state);1308 state = REG_GET_MASK(r, SENSOR_CONFIG2_THERMB_MASK);1309 seq_printf(s, "%d)\n", (s16)state);1310 }1311 1312 r = readl(ts->regs + SENSOR_PDIV);1313 seq_printf(s, "PDIV: 0x%x\n", r);1314 1315 r = readl(ts->regs + SENSOR_HOTSPOT_OFF);1316 seq_printf(s, "HOTSPOT: 0x%x\n", r);1317 1318 seq_puts(s, "\n");1319 seq_puts(s, "-----SOC_THERM-----\n");1320 1321 r = readl(ts->regs + SENSOR_TEMP1);1322 state = REG_GET_MASK(r, SENSOR_TEMP1_CPU_TEMP_MASK);1323 seq_printf(s, "Temperatures: CPU(%d) ", translate_temp(state));1324 state = REG_GET_MASK(r, SENSOR_TEMP1_GPU_TEMP_MASK);1325 seq_printf(s, " GPU(%d) ", translate_temp(state));1326 r = readl(ts->regs + SENSOR_TEMP2);1327 state = REG_GET_MASK(r, SENSOR_TEMP2_PLLX_TEMP_MASK);1328 seq_printf(s, " PLLX(%d) ", translate_temp(state));1329 state = REG_GET_MASK(r, SENSOR_TEMP2_MEM_TEMP_MASK);1330 seq_printf(s, " MEM(%d)\n", translate_temp(state));1331 1332 for (i = 0; i < ts->soc->num_ttgs; i++) {1333 seq_printf(s, "%s:\n", ttgs[i]->name);1334 for (level = 0; level < 4; level++) {1335 s32 v;1336 u32 mask;1337 u16 off = ttgs[i]->thermctl_lvl0_offset;1338 1339 r = readl(ts->regs + THERMCTL_LVL_REG(off, level));1340 1341 mask = ttgs[i]->thermctl_lvl0_up_thresh_mask;1342 state = REG_GET_MASK(r, mask);1343 v = sign_extend32(state, ts->soc->bptt - 1);1344 v *= ts->soc->thresh_grain;1345 seq_printf(s, " %d: Up/Dn(%d /", level, v);1346 1347 mask = ttgs[i]->thermctl_lvl0_dn_thresh_mask;1348 state = REG_GET_MASK(r, mask);1349 v = sign_extend32(state, ts->soc->bptt - 1);1350 v *= ts->soc->thresh_grain;1351 seq_printf(s, "%d ) ", v);1352 1353 mask = THERMCTL_LVL0_CPU0_EN_MASK;1354 state = REG_GET_MASK(r, mask);1355 seq_printf(s, "En(%d) ", state);1356 1357 mask = THERMCTL_LVL0_CPU0_CPU_THROT_MASK;1358 state = REG_GET_MASK(r, mask);1359 seq_puts(s, "CPU Throt");1360 if (!state)1361 seq_printf(s, "(%s) ", "none");1362 else if (state == THERMCTL_LVL0_CPU0_CPU_THROT_LIGHT)1363 seq_printf(s, "(%s) ", "L");1364 else if (state == THERMCTL_LVL0_CPU0_CPU_THROT_HEAVY)1365 seq_printf(s, "(%s) ", "H");1366 else1367 seq_printf(s, "(%s) ", "H+L");1368 1369 mask = THERMCTL_LVL0_CPU0_GPU_THROT_MASK;1370 state = REG_GET_MASK(r, mask);1371 seq_puts(s, "GPU Throt");1372 if (!state)1373 seq_printf(s, "(%s) ", "none");1374 else if (state == THERMCTL_LVL0_CPU0_GPU_THROT_LIGHT)1375 seq_printf(s, "(%s) ", "L");1376 else if (state == THERMCTL_LVL0_CPU0_GPU_THROT_HEAVY)1377 seq_printf(s, "(%s) ", "H");1378 else1379 seq_printf(s, "(%s) ", "H+L");1380 1381 mask = THERMCTL_LVL0_CPU0_STATUS_MASK;1382 state = REG_GET_MASK(r, mask);1383 seq_printf(s, "Status(%s)\n",1384 state == 0 ? "LO" :1385 state == 1 ? "In" :1386 state == 2 ? "Res" : "HI");1387 }1388 }1389 1390 r = readl(ts->regs + THERMCTL_STATS_CTL);1391 seq_printf(s, "STATS: Up(%s) Dn(%s)\n",1392 r & STATS_CTL_EN_UP ? "En" : "--",1393 r & STATS_CTL_EN_DN ? "En" : "--");1394 1395 for (level = 0; level < 4; level++) {1396 u16 off;1397 1398 off = THERMCTL_LVL0_UP_STATS;1399 r = readl(ts->regs + THERMCTL_LVL_REG(off, level));1400 seq_printf(s, " Level_%d Up(%d) ", level, r);1401 1402 off = THERMCTL_LVL0_DN_STATS;1403 r = readl(ts->regs + THERMCTL_LVL_REG(off, level));1404 seq_printf(s, "Dn(%d)\n", r);1405 }1406 1407 r = readl(ts->regs + THERMCTL_THERMTRIP_CTL);1408 state = REG_GET_MASK(r, ttgs[0]->thermtrip_any_en_mask);1409 seq_printf(s, "Thermtrip Any En(%d)\n", state);1410 for (i = 0; i < ts->soc->num_ttgs; i++) {1411 state = REG_GET_MASK(r, ttgs[i]->thermtrip_enable_mask);1412 seq_printf(s, " %s En(%d) ", ttgs[i]->name, state);1413 state = REG_GET_MASK(r, ttgs[i]->thermtrip_threshold_mask);1414 state *= ts->soc->thresh_grain;1415 seq_printf(s, "Thresh(%d)\n", state);1416 }1417 1418 r = readl(ts->regs + THROT_GLOBAL_CFG);1419 seq_puts(s, "\n");1420 seq_printf(s, "GLOBAL THROTTLE CONFIG: 0x%08x\n", r);1421 1422 seq_puts(s, "---------------------------------------------------\n");1423 r = readl(ts->regs + THROT_STATUS);1424 state = REG_GET_MASK(r, THROT_STATUS_BREACH_MASK);1425 seq_printf(s, "THROT STATUS: breach(%d) ", state);1426 state = REG_GET_MASK(r, THROT_STATUS_STATE_MASK);1427 seq_printf(s, "state(%d) ", state);1428 state = REG_GET_MASK(r, THROT_STATUS_ENABLED_MASK);1429 seq_printf(s, "enabled(%d)\n", state);1430 1431 r = readl(ts->regs + CPU_PSKIP_STATUS);1432 if (ts->soc->use_ccroc) {1433 state = REG_GET_MASK(r, XPU_PSKIP_STATUS_ENABLED_MASK);1434 seq_printf(s, "CPU PSKIP STATUS: enabled(%d)\n", state);1435 } else {1436 state = REG_GET_MASK(r, XPU_PSKIP_STATUS_M_MASK);1437 seq_printf(s, "CPU PSKIP STATUS: M(%d) ", state);1438 state = REG_GET_MASK(r, XPU_PSKIP_STATUS_N_MASK);1439 seq_printf(s, "N(%d) ", state);1440 state = REG_GET_MASK(r, XPU_PSKIP_STATUS_ENABLED_MASK);1441 seq_printf(s, "enabled(%d)\n", state);1442 }1443 1444 return 0;1445}1446 1447DEFINE_SHOW_ATTRIBUTE(regs);1448 1449static void soctherm_debug_init(struct platform_device *pdev)1450{1451 struct tegra_soctherm *tegra = platform_get_drvdata(pdev);1452 struct dentry *root;1453 1454 root = debugfs_create_dir("soctherm", NULL);1455 1456 tegra->debugfs_dir = root;1457 1458 debugfs_create_file("reg_contents", 0644, root, pdev, ®s_fops);1459}1460#else1461static inline void soctherm_debug_init(struct platform_device *pdev) {}1462#endif1463 1464static int soctherm_clk_enable(struct platform_device *pdev, bool enable)1465{1466 struct tegra_soctherm *tegra = platform_get_drvdata(pdev);1467 int err;1468 1469 if (!tegra->clock_soctherm || !tegra->clock_tsensor)1470 return -EINVAL;1471 1472 reset_control_assert(tegra->reset);1473 1474 if (enable) {1475 err = clk_prepare_enable(tegra->clock_soctherm);1476 if (err) {1477 reset_control_deassert(tegra->reset);1478 return err;1479 }1480 1481 err = clk_prepare_enable(tegra->clock_tsensor);1482 if (err) {1483 clk_disable_unprepare(tegra->clock_soctherm);1484 reset_control_deassert(tegra->reset);1485 return err;1486 }1487 } else {1488 clk_disable_unprepare(tegra->clock_tsensor);1489 clk_disable_unprepare(tegra->clock_soctherm);1490 }1491 1492 reset_control_deassert(tegra->reset);1493 1494 return 0;1495}1496 1497static int throt_get_cdev_max_state(struct thermal_cooling_device *cdev,1498 unsigned long *max_state)1499{1500 *max_state = 1;1501 return 0;1502}1503 1504static int throt_get_cdev_cur_state(struct thermal_cooling_device *cdev,1505 unsigned long *cur_state)1506{1507 struct tegra_soctherm *ts = cdev->devdata;1508 u32 r;1509 1510 r = readl(ts->regs + THROT_STATUS);1511 if (REG_GET_MASK(r, THROT_STATUS_STATE_MASK))1512 *cur_state = 1;1513 else1514 *cur_state = 0;1515 1516 return 0;1517}1518 1519static int throt_set_cdev_state(struct thermal_cooling_device *cdev,1520 unsigned long cur_state)1521{1522 return 0;1523}1524 1525static const struct thermal_cooling_device_ops throt_cooling_ops = {1526 .get_max_state = throt_get_cdev_max_state,1527 .get_cur_state = throt_get_cdev_cur_state,1528 .set_cur_state = throt_set_cdev_state,1529};1530 1531static int soctherm_thermtrips_parse(struct platform_device *pdev)1532{1533 struct device *dev = &pdev->dev;1534 struct tegra_soctherm *ts = dev_get_drvdata(dev);1535 struct tsensor_group_thermtrips *tt = ts->soc->thermtrips;1536 const int max_num_prop = ts->soc->num_ttgs * 2;1537 u32 *tlb;1538 int i, j, n, ret;1539 1540 if (!tt)1541 return -ENOMEM;1542 1543 n = of_property_count_u32_elems(dev->of_node, "nvidia,thermtrips");1544 if (n <= 0) {1545 dev_info(dev,1546 "missing thermtrips, will use critical trips as shut down temp\n");1547 return n;1548 }1549 1550 n = min(max_num_prop, n);1551 1552 tlb = devm_kcalloc(&pdev->dev, max_num_prop, sizeof(u32), GFP_KERNEL);1553 if (!tlb)1554 return -ENOMEM;1555 ret = of_property_read_u32_array(dev->of_node, "nvidia,thermtrips",1556 tlb, n);1557 if (ret) {1558 dev_err(dev, "invalid num ele: thermtrips:%d\n", ret);1559 return ret;1560 }1561 1562 i = 0;1563 for (j = 0; j < n; j = j + 2) {1564 if (tlb[j] >= TEGRA124_SOCTHERM_SENSOR_NUM)1565 continue;1566 1567 tt[i].id = tlb[j];1568 tt[i].temp = tlb[j + 1];1569 i++;1570 }1571 1572 return 0;1573}1574 1575static void soctherm_oc_cfg_parse(struct device *dev,1576 struct device_node *np_oc,1577 struct soctherm_throt_cfg *stc)1578{1579 u32 val;1580 1581 if (of_property_read_bool(np_oc, "nvidia,polarity-active-low"))1582 stc->oc_cfg.active_low = 1;1583 else1584 stc->oc_cfg.active_low = 0;1585 1586 if (!of_property_read_u32(np_oc, "nvidia,count-threshold", &val)) {1587 stc->oc_cfg.intr_en = 1;1588 stc->oc_cfg.alarm_cnt_thresh = val;1589 }1590 1591 if (!of_property_read_u32(np_oc, "nvidia,throttle-period-us", &val))1592 stc->oc_cfg.throt_period = val;1593 1594 if (!of_property_read_u32(np_oc, "nvidia,alarm-filter", &val))1595 stc->oc_cfg.alarm_filter = val;1596 1597 /* BRIEF throttling by default, do not support STICKY */1598 stc->oc_cfg.mode = OC_THROTTLE_MODE_BRIEF;1599}1600 1601static int soctherm_throt_cfg_parse(struct device *dev,1602 struct device_node *np,1603 struct soctherm_throt_cfg *stc)1604{1605 struct tegra_soctherm *ts = dev_get_drvdata(dev);1606 int ret;1607 u32 val;1608 1609 ret = of_property_read_u32(np, "nvidia,priority", &val);1610 if (ret) {1611 dev_err(dev, "throttle-cfg: %s: invalid priority\n", stc->name);1612 return -EINVAL;1613 }1614 stc->priority = val;1615 1616 ret = of_property_read_u32(np, ts->soc->use_ccroc ?1617 "nvidia,cpu-throt-level" :1618 "nvidia,cpu-throt-percent", &val);1619 if (!ret) {1620 if (ts->soc->use_ccroc &&1621 val <= TEGRA_SOCTHERM_THROT_LEVEL_HIGH)1622 stc->cpu_throt_level = val;1623 else if (!ts->soc->use_ccroc && val <= 100)1624 stc->cpu_throt_depth = val;1625 else1626 goto err;1627 } else {1628 goto err;1629 }1630 1631 ret = of_property_read_u32(np, "nvidia,gpu-throt-level", &val);1632 if (!ret && val <= TEGRA_SOCTHERM_THROT_LEVEL_HIGH)1633 stc->gpu_throt_level = val;1634 else1635 goto err;1636 1637 return 0;1638 1639err:1640 dev_err(dev, "throttle-cfg: %s: no throt prop or invalid prop\n",1641 stc->name);1642 return -EINVAL;1643}1644 1645/**1646 * soctherm_init_hw_throt_cdev() - Parse the HW throttle configurations1647 * and register them as cooling devices.1648 * @pdev: Pointer to platform_device struct1649 */1650static void soctherm_init_hw_throt_cdev(struct platform_device *pdev)1651{1652 struct device *dev = &pdev->dev;1653 struct tegra_soctherm *ts = dev_get_drvdata(dev);1654 struct device_node *np_stc, *np_stcc;1655 const char *name;1656 int i;1657 1658 for (i = 0; i < THROTTLE_SIZE; i++) {1659 ts->throt_cfgs[i].name = throt_names[i];1660 ts->throt_cfgs[i].id = i;1661 ts->throt_cfgs[i].init = false;1662 }1663 1664 np_stc = of_get_child_by_name(dev->of_node, "throttle-cfgs");1665 if (!np_stc) {1666 dev_info(dev,1667 "throttle-cfg: no throttle-cfgs - not enabling\n");1668 return;1669 }1670 1671 for_each_child_of_node(np_stc, np_stcc) {1672 struct soctherm_throt_cfg *stc;1673 struct thermal_cooling_device *tcd;1674 int err;1675 1676 name = np_stcc->name;1677 stc = find_throttle_cfg_by_name(ts, name);1678 if (!stc) {1679 dev_err(dev,1680 "throttle-cfg: could not find %s\n", name);1681 continue;1682 }1683 1684 if (stc->init) {1685 dev_err(dev, "throttle-cfg: %s: redefined!\n", name);1686 of_node_put(np_stcc);1687 break;1688 }1689 1690 err = soctherm_throt_cfg_parse(dev, np_stcc, stc);1691 if (err)1692 continue;1693 1694 if (stc->id >= THROTTLE_OC1) {1695 soctherm_oc_cfg_parse(dev, np_stcc, stc);1696 stc->init = true;1697 } else {1698 1699 tcd = thermal_of_cooling_device_register(np_stcc,1700 (char *)name, ts,1701 &throt_cooling_ops);1702 if (IS_ERR_OR_NULL(tcd)) {1703 dev_err(dev,1704 "throttle-cfg: %s: failed to register cooling device\n",1705 name);1706 continue;1707 }1708 stc->cdev = tcd;1709 stc->init = true;1710 }1711 1712 }1713 1714 of_node_put(np_stc);1715}1716 1717/**1718 * throttlectl_cpu_level_cfg() - programs CCROC NV_THERM level config1719 * @ts: pointer to a struct tegra_soctherm1720 * @level: describing the level LOW/MED/HIGH of throttling1721 *1722 * It's necessary to set up the CPU-local CCROC NV_THERM instance with1723 * the M/N values desired for each level. This function does this.1724 *1725 * This function pre-programs the CCROC NV_THERM levels in terms of1726 * pre-configured "Low", "Medium" or "Heavy" throttle levels which are1727 * mapped to THROT_LEVEL_LOW, THROT_LEVEL_MED and THROT_LEVEL_HVY.1728 */1729static void throttlectl_cpu_level_cfg(struct tegra_soctherm *ts, int level)1730{1731 u8 depth, dividend;1732 u32 r;1733 1734 switch (level) {1735 case TEGRA_SOCTHERM_THROT_LEVEL_LOW:1736 depth = 50;1737 break;1738 case TEGRA_SOCTHERM_THROT_LEVEL_MED:1739 depth = 75;1740 break;1741 case TEGRA_SOCTHERM_THROT_LEVEL_HIGH:1742 depth = 80;1743 break;1744 case TEGRA_SOCTHERM_THROT_LEVEL_NONE:1745 return;1746 default:1747 return;1748 }1749 1750 dividend = THROT_DEPTH_DIVIDEND(depth);1751 1752 /* setup PSKIP in ccroc nv_therm registers */1753 r = ccroc_readl(ts, CCROC_THROT_PSKIP_RAMP_CPU_REG(level));1754 r = REG_SET_MASK(r, CCROC_THROT_PSKIP_RAMP_DURATION_MASK, 0xff);1755 r = REG_SET_MASK(r, CCROC_THROT_PSKIP_RAMP_STEP_MASK, 0xf);1756 ccroc_writel(ts, r, CCROC_THROT_PSKIP_RAMP_CPU_REG(level));1757 1758 r = ccroc_readl(ts, CCROC_THROT_PSKIP_CTRL_CPU_REG(level));1759 r = REG_SET_MASK(r, CCROC_THROT_PSKIP_CTRL_ENB_MASK, 1);1760 r = REG_SET_MASK(r, CCROC_THROT_PSKIP_CTRL_DIVIDEND_MASK, dividend);1761 r = REG_SET_MASK(r, CCROC_THROT_PSKIP_CTRL_DIVISOR_MASK, 0xff);1762 ccroc_writel(ts, r, CCROC_THROT_PSKIP_CTRL_CPU_REG(level));1763}1764 1765/**1766 * throttlectl_cpu_level_select() - program CPU pulse skipper config1767 * @ts: pointer to a struct tegra_soctherm1768 * @throt: the LIGHT/HEAVY of throttle event id1769 *1770 * Pulse skippers are used to throttle clock frequencies. This1771 * function programs the pulse skippers based on @throt and platform1772 * data. This function is used on SoCs which have CPU-local pulse1773 * skipper control, such as T13x. It programs soctherm's interface to1774 * Denver:CCROC NV_THERM in terms of Low, Medium and HIGH throttling1775 * vectors. PSKIP_BYPASS mode is set as required per HW spec.1776 */1777static void throttlectl_cpu_level_select(struct tegra_soctherm *ts,1778 enum soctherm_throttle_id throt)1779{1780 u32 r, throt_vect;1781 1782 /* Denver:CCROC NV_THERM interface N:3 Mapping */1783 switch (ts->throt_cfgs[throt].cpu_throt_level) {1784 case TEGRA_SOCTHERM_THROT_LEVEL_LOW:1785 throt_vect = THROT_VECT_LOW;1786 break;1787 case TEGRA_SOCTHERM_THROT_LEVEL_MED:1788 throt_vect = THROT_VECT_MED;1789 break;1790 case TEGRA_SOCTHERM_THROT_LEVEL_HIGH:1791 throt_vect = THROT_VECT_HIGH;1792 break;1793 default:1794 throt_vect = THROT_VECT_NONE;1795 break;1796 }1797 1798 r = readl(ts->regs + THROT_PSKIP_CTRL(throt, THROTTLE_DEV_CPU));1799 r = REG_SET_MASK(r, THROT_PSKIP_CTRL_ENABLE_MASK, 1);1800 r = REG_SET_MASK(r, THROT_PSKIP_CTRL_VECT_CPU_MASK, throt_vect);1801 r = REG_SET_MASK(r, THROT_PSKIP_CTRL_VECT2_CPU_MASK, throt_vect);1802 writel(r, ts->regs + THROT_PSKIP_CTRL(throt, THROTTLE_DEV_CPU));1803 1804 /* bypass sequencer in soc_therm as it is programmed in ccroc */1805 r = REG_SET_MASK(0, THROT_PSKIP_RAMP_SEQ_BYPASS_MODE_MASK, 1);1806 writel(r, ts->regs + THROT_PSKIP_RAMP(throt, THROTTLE_DEV_CPU));1807}1808 1809/**1810 * throttlectl_cpu_mn() - program CPU pulse skipper configuration1811 * @ts: pointer to a struct tegra_soctherm1812 * @throt: the LIGHT/HEAVY of throttle event id1813 *1814 * Pulse skippers are used to throttle clock frequencies. This1815 * function programs the pulse skippers based on @throt and platform1816 * data. This function is used for CPUs that have "remote" pulse1817 * skipper control, e.g., the CPU pulse skipper is controlled by the1818 * SOC_THERM IP block. (SOC_THERM is located outside the CPU1819 * complex.)1820 */1821static void throttlectl_cpu_mn(struct tegra_soctherm *ts,1822 enum soctherm_throttle_id throt)1823{1824 u32 r;1825 int depth;1826 u8 dividend;1827 1828 depth = ts->throt_cfgs[throt].cpu_throt_depth;1829 dividend = THROT_DEPTH_DIVIDEND(depth);1830 1831 r = readl(ts->regs + THROT_PSKIP_CTRL(throt, THROTTLE_DEV_CPU));1832 r = REG_SET_MASK(r, THROT_PSKIP_CTRL_ENABLE_MASK, 1);1833 r = REG_SET_MASK(r, THROT_PSKIP_CTRL_DIVIDEND_MASK, dividend);1834 r = REG_SET_MASK(r, THROT_PSKIP_CTRL_DIVISOR_MASK, 0xff);1835 writel(r, ts->regs + THROT_PSKIP_CTRL(throt, THROTTLE_DEV_CPU));1836 1837 r = readl(ts->regs + THROT_PSKIP_RAMP(throt, THROTTLE_DEV_CPU));1838 r = REG_SET_MASK(r, THROT_PSKIP_RAMP_DURATION_MASK, 0xff);1839 r = REG_SET_MASK(r, THROT_PSKIP_RAMP_STEP_MASK, 0xf);1840 writel(r, ts->regs + THROT_PSKIP_RAMP(throt, THROTTLE_DEV_CPU));1841}1842 1843/**1844 * throttlectl_gpu_level_select() - selects throttling level for GPU1845 * @ts: pointer to a struct tegra_soctherm1846 * @throt: the LIGHT/HEAVY of throttle event id1847 *1848 * This function programs soctherm's interface to GK20a NV_THERM to select1849 * pre-configured "Low", "Medium" or "Heavy" throttle levels.1850 *1851 * Return: boolean true if HW was programmed1852 */1853static void throttlectl_gpu_level_select(struct tegra_soctherm *ts,1854 enum soctherm_throttle_id throt)1855{1856 u32 r, level, throt_vect;1857 1858 level = ts->throt_cfgs[throt].gpu_throt_level;1859 throt_vect = THROT_LEVEL_TO_DEPTH(level);1860 r = readl(ts->regs + THROT_PSKIP_CTRL(throt, THROTTLE_DEV_GPU));1861 r = REG_SET_MASK(r, THROT_PSKIP_CTRL_ENABLE_MASK, 1);1862 r = REG_SET_MASK(r, THROT_PSKIP_CTRL_VECT_GPU_MASK, throt_vect);1863 writel(r, ts->regs + THROT_PSKIP_CTRL(throt, THROTTLE_DEV_GPU));1864}1865 1866static int soctherm_oc_cfg_program(struct tegra_soctherm *ts,1867 enum soctherm_throttle_id throt)1868{1869 u32 r;1870 struct soctherm_oc_cfg *oc = &ts->throt_cfgs[throt].oc_cfg;1871 1872 if (oc->mode == OC_THROTTLE_MODE_DISABLED)1873 return -EINVAL;1874 1875 r = REG_SET_MASK(0, OC1_CFG_HW_RESTORE_MASK, 1);1876 r = REG_SET_MASK(r, OC1_CFG_THROTTLE_MODE_MASK, oc->mode);1877 r = REG_SET_MASK(r, OC1_CFG_ALARM_POLARITY_MASK, oc->active_low);1878 r = REG_SET_MASK(r, OC1_CFG_EN_THROTTLE_MASK, 1);1879 writel(r, ts->regs + ALARM_CFG(throt));1880 writel(oc->throt_period, ts->regs + ALARM_THROTTLE_PERIOD(throt));1881 writel(oc->alarm_cnt_thresh, ts->regs + ALARM_CNT_THRESHOLD(throt));1882 writel(oc->alarm_filter, ts->regs + ALARM_FILTER(throt));1883 soctherm_oc_intr_enable(ts, throt, oc->intr_en);1884 1885 return 0;1886}1887 1888/**1889 * soctherm_throttle_program() - programs pulse skippers' configuration1890 * @ts: pointer to a struct tegra_soctherm1891 * @throt: the LIGHT/HEAVY of the throttle event id.1892 *1893 * Pulse skippers are used to throttle clock frequencies.1894 * This function programs the pulse skippers.1895 */1896static void soctherm_throttle_program(struct tegra_soctherm *ts,1897 enum soctherm_throttle_id throt)1898{1899 u32 r;1900 struct soctherm_throt_cfg stc = ts->throt_cfgs[throt];1901 1902 if (!stc.init)1903 return;1904 1905 if ((throt >= THROTTLE_OC1) && (soctherm_oc_cfg_program(ts, throt)))1906 return;1907 1908 /* Setup PSKIP parameters */1909 if (ts->soc->use_ccroc)1910 throttlectl_cpu_level_select(ts, throt);1911 else1912 throttlectl_cpu_mn(ts, throt);1913 1914 throttlectl_gpu_level_select(ts, throt);1915 1916 r = REG_SET_MASK(0, THROT_PRIORITY_LITE_PRIO_MASK, stc.priority);1917 writel(r, ts->regs + THROT_PRIORITY_CTRL(throt));1918 1919 r = REG_SET_MASK(0, THROT_DELAY_LITE_DELAY_MASK, 0);1920 writel(r, ts->regs + THROT_DELAY_CTRL(throt));1921 1922 r = readl(ts->regs + THROT_PRIORITY_LOCK);1923 r = REG_GET_MASK(r, THROT_PRIORITY_LOCK_PRIORITY_MASK);1924 if (r >= stc.priority)1925 return;1926 r = REG_SET_MASK(0, THROT_PRIORITY_LOCK_PRIORITY_MASK,1927 stc.priority);1928 writel(r, ts->regs + THROT_PRIORITY_LOCK);1929}1930 1931static void tegra_soctherm_throttle(struct device *dev)1932{1933 struct tegra_soctherm *ts = dev_get_drvdata(dev);1934 u32 v;1935 int i;1936 1937 /* configure LOW, MED and HIGH levels for CCROC NV_THERM */1938 if (ts->soc->use_ccroc) {1939 throttlectl_cpu_level_cfg(ts, TEGRA_SOCTHERM_THROT_LEVEL_LOW);1940 throttlectl_cpu_level_cfg(ts, TEGRA_SOCTHERM_THROT_LEVEL_MED);1941 throttlectl_cpu_level_cfg(ts, TEGRA_SOCTHERM_THROT_LEVEL_HIGH);1942 }1943 1944 /* Thermal HW throttle programming */1945 for (i = 0; i < THROTTLE_SIZE; i++)1946 soctherm_throttle_program(ts, i);1947 1948 v = REG_SET_MASK(0, THROT_GLOBAL_ENB_MASK, 1);1949 if (ts->soc->use_ccroc) {1950 ccroc_writel(ts, v, CCROC_GLOBAL_CFG);1951 1952 v = ccroc_readl(ts, CCROC_SUPER_CCLKG_DIVIDER);1953 v = REG_SET_MASK(v, CDIVG_USE_THERM_CONTROLS_MASK, 1);1954 ccroc_writel(ts, v, CCROC_SUPER_CCLKG_DIVIDER);1955 } else {1956 writel(v, ts->regs + THROT_GLOBAL_CFG);1957 1958 v = readl(ts->clk_regs + CAR_SUPER_CCLKG_DIVIDER);1959 v = REG_SET_MASK(v, CDIVG_USE_THERM_CONTROLS_MASK, 1);1960 writel(v, ts->clk_regs + CAR_SUPER_CCLKG_DIVIDER);1961 }1962 1963 /* initialize stats collection */1964 v = STATS_CTL_CLR_DN | STATS_CTL_EN_DN |1965 STATS_CTL_CLR_UP | STATS_CTL_EN_UP;1966 writel(v, ts->regs + THERMCTL_STATS_CTL);1967}1968 1969static int soctherm_interrupts_init(struct platform_device *pdev,1970 struct tegra_soctherm *tegra)1971{1972 struct device_node *np = pdev->dev.of_node;1973 int ret;1974 1975 ret = soctherm_oc_int_init(np, TEGRA_SOC_OC_IRQ_MAX);1976 if (ret < 0) {1977 dev_err(&pdev->dev, "soctherm_oc_int_init failed\n");1978 return ret;1979 }1980 1981 tegra->thermal_irq = platform_get_irq(pdev, 0);1982 if (tegra->thermal_irq < 0) {1983 dev_dbg(&pdev->dev, "get 'thermal_irq' failed.\n");1984 return 0;1985 }1986 1987 tegra->edp_irq = platform_get_irq(pdev, 1);1988 if (tegra->edp_irq < 0) {1989 dev_dbg(&pdev->dev, "get 'edp_irq' failed.\n");1990 return 0;1991 }1992 1993 ret = devm_request_threaded_irq(&pdev->dev,1994 tegra->thermal_irq,1995 soctherm_thermal_isr,1996 soctherm_thermal_isr_thread,1997 IRQF_ONESHOT,1998 dev_name(&pdev->dev),1999 tegra);2000 if (ret < 0) {2001 dev_err(&pdev->dev, "request_irq 'thermal_irq' failed.\n");2002 return ret;2003 }2004 2005 ret = devm_request_threaded_irq(&pdev->dev,2006 tegra->edp_irq,2007 soctherm_edp_isr,2008 soctherm_edp_isr_thread,2009 IRQF_ONESHOT,2010 "soctherm_edp",2011 tegra);2012 if (ret < 0) {2013 dev_err(&pdev->dev, "request_irq 'edp_irq' failed.\n");2014 return ret;2015 }2016 2017 return 0;2018}2019 2020static void soctherm_init(struct platform_device *pdev)2021{2022 struct tegra_soctherm *tegra = platform_get_drvdata(pdev);2023 const struct tegra_tsensor_group **ttgs = tegra->soc->ttgs;2024 int i;2025 u32 pdiv, hotspot;2026 2027 /* Initialize raw sensors */2028 for (i = 0; i < tegra->soc->num_tsensors; ++i)2029 enable_tsensor(tegra, i);2030 2031 /* program pdiv and hotspot offsets per THERM */2032 pdiv = readl(tegra->regs + SENSOR_PDIV);2033 hotspot = readl(tegra->regs + SENSOR_HOTSPOT_OFF);2034 for (i = 0; i < tegra->soc->num_ttgs; ++i) {2035 pdiv = REG_SET_MASK(pdiv, ttgs[i]->pdiv_mask,2036 ttgs[i]->pdiv);2037 /* hotspot offset from PLLX, doesn't need to configure PLLX */2038 if (ttgs[i]->id == TEGRA124_SOCTHERM_SENSOR_PLLX)2039 continue;2040 hotspot = REG_SET_MASK(hotspot,2041 ttgs[i]->pllx_hotspot_mask,2042 ttgs[i]->pllx_hotspot_diff);2043 }2044 writel(pdiv, tegra->regs + SENSOR_PDIV);2045 writel(hotspot, tegra->regs + SENSOR_HOTSPOT_OFF);2046 2047 /* Configure hw throttle */2048 tegra_soctherm_throttle(&pdev->dev);2049}2050 2051static const struct of_device_id tegra_soctherm_of_match[] = {2052#ifdef CONFIG_ARCH_TEGRA_124_SOC2053 {2054 .compatible = "nvidia,tegra124-soctherm",2055 .data = &tegra124_soctherm,2056 },2057#endif2058#ifdef CONFIG_ARCH_TEGRA_132_SOC2059 {2060 .compatible = "nvidia,tegra132-soctherm",2061 .data = &tegra132_soctherm,2062 },2063#endif2064#ifdef CONFIG_ARCH_TEGRA_210_SOC2065 {2066 .compatible = "nvidia,tegra210-soctherm",2067 .data = &tegra210_soctherm,2068 },2069#endif2070 { },2071};2072MODULE_DEVICE_TABLE(of, tegra_soctherm_of_match);2073 2074static int tegra_soctherm_probe(struct platform_device *pdev)2075{2076 const struct of_device_id *match;2077 struct tegra_soctherm *tegra;2078 struct thermal_zone_device *z;2079 struct tsensor_shared_calib shared_calib;2080 struct tegra_soctherm_soc *soc;2081 unsigned int i;2082 int err;2083 2084 match = of_match_node(tegra_soctherm_of_match, pdev->dev.of_node);2085 if (!match)2086 return -ENODEV;2087 2088 soc = (struct tegra_soctherm_soc *)match->data;2089 if (soc->num_ttgs > TEGRA124_SOCTHERM_SENSOR_NUM)2090 return -EINVAL;2091 2092 tegra = devm_kzalloc(&pdev->dev, sizeof(*tegra), GFP_KERNEL);2093 if (!tegra)2094 return -ENOMEM;2095 2096 mutex_init(&tegra->thermctl_lock);2097 dev_set_drvdata(&pdev->dev, tegra);2098 2099 tegra->soc = soc;2100 2101 tegra->regs = devm_platform_ioremap_resource_byname(pdev, "soctherm-reg");2102 if (IS_ERR(tegra->regs)) {2103 dev_err(&pdev->dev, "can't get soctherm registers");2104 return PTR_ERR(tegra->regs);2105 }2106 2107 if (!tegra->soc->use_ccroc) {2108 tegra->clk_regs = devm_platform_ioremap_resource_byname(pdev, "car-reg");2109 if (IS_ERR(tegra->clk_regs)) {2110 dev_err(&pdev->dev, "can't get car clk registers");2111 return PTR_ERR(tegra->clk_regs);2112 }2113 } else {2114 tegra->ccroc_regs = devm_platform_ioremap_resource_byname(pdev, "ccroc-reg");2115 if (IS_ERR(tegra->ccroc_regs)) {2116 dev_err(&pdev->dev, "can't get ccroc registers");2117 return PTR_ERR(tegra->ccroc_regs);2118 }2119 }2120 2121 tegra->reset = devm_reset_control_get(&pdev->dev, "soctherm");2122 if (IS_ERR(tegra->reset)) {2123 dev_err(&pdev->dev, "can't get soctherm reset\n");2124 return PTR_ERR(tegra->reset);2125 }2126 2127 tegra->clock_tsensor = devm_clk_get(&pdev->dev, "tsensor");2128 if (IS_ERR(tegra->clock_tsensor)) {2129 dev_err(&pdev->dev, "can't get tsensor clock\n");2130 return PTR_ERR(tegra->clock_tsensor);2131 }2132 2133 tegra->clock_soctherm = devm_clk_get(&pdev->dev, "soctherm");2134 if (IS_ERR(tegra->clock_soctherm)) {2135 dev_err(&pdev->dev, "can't get soctherm clock\n");2136 return PTR_ERR(tegra->clock_soctherm);2137 }2138 2139 tegra->calib = devm_kcalloc(&pdev->dev,2140 soc->num_tsensors, sizeof(u32),2141 GFP_KERNEL);2142 if (!tegra->calib)2143 return -ENOMEM;2144 2145 /* calculate shared calibration data */2146 err = tegra_calc_shared_calib(soc->tfuse, &shared_calib);2147 if (err)2148 return err;2149 2150 /* calculate tsensor calibration data */2151 for (i = 0; i < soc->num_tsensors; ++i) {2152 err = tegra_calc_tsensor_calib(&soc->tsensors[i],2153 &shared_calib,2154 &tegra->calib[i]);2155 if (err)2156 return err;2157 }2158 2159 tegra->thermctl_tzs = devm_kcalloc(&pdev->dev,2160 soc->num_ttgs, sizeof(z),2161 GFP_KERNEL);2162 if (!tegra->thermctl_tzs)2163 return -ENOMEM;2164 2165 err = soctherm_clk_enable(pdev, true);2166 if (err)2167 return err;2168 2169 soctherm_thermtrips_parse(pdev);2170 2171 soctherm_init_hw_throt_cdev(pdev);2172 2173 soctherm_init(pdev);2174 2175 for (i = 0; i < soc->num_ttgs; ++i) {2176 struct tegra_thermctl_zone *zone =2177 devm_kzalloc(&pdev->dev, sizeof(*zone), GFP_KERNEL);2178 if (!zone) {2179 err = -ENOMEM;2180 goto disable_clocks;2181 }2182 2183 zone->reg = tegra->regs + soc->ttgs[i]->sensor_temp_offset;2184 zone->dev = &pdev->dev;2185 zone->sg = soc->ttgs[i];2186 zone->ts = tegra;2187 2188 z = devm_thermal_of_zone_register(&pdev->dev,2189 soc->ttgs[i]->id, zone,2190 &tegra_of_thermal_ops);2191 if (IS_ERR(z)) {2192 err = PTR_ERR(z);2193 dev_err(&pdev->dev, "failed to register sensor: %d\n",2194 err);2195 goto disable_clocks;2196 }2197 2198 zone->tz = z;2199 tegra->thermctl_tzs[soc->ttgs[i]->id] = z;2200 2201 /* Configure hw trip points */2202 err = tegra_soctherm_set_hwtrips(&pdev->dev, soc->ttgs[i], z);2203 if (err)2204 goto disable_clocks;2205 }2206 2207 err = soctherm_interrupts_init(pdev, tegra);2208 2209 soctherm_debug_init(pdev);2210 2211 return 0;2212 2213disable_clocks:2214 soctherm_clk_enable(pdev, false);2215 2216 return err;2217}2218 2219static void tegra_soctherm_remove(struct platform_device *pdev)2220{2221 struct tegra_soctherm *tegra = platform_get_drvdata(pdev);2222 2223 debugfs_remove_recursive(tegra->debugfs_dir);2224 2225 soctherm_clk_enable(pdev, false);2226}2227 2228static int __maybe_unused soctherm_suspend(struct device *dev)2229{2230 struct platform_device *pdev = to_platform_device(dev);2231 2232 soctherm_clk_enable(pdev, false);2233 2234 return 0;2235}2236 2237static int __maybe_unused soctherm_resume(struct device *dev)2238{2239 struct platform_device *pdev = to_platform_device(dev);2240 struct tegra_soctherm *tegra = platform_get_drvdata(pdev);2241 struct tegra_soctherm_soc *soc = tegra->soc;2242 int err, i;2243 2244 err = soctherm_clk_enable(pdev, true);2245 if (err) {2246 dev_err(&pdev->dev,2247 "Resume failed: enable clocks failed\n");2248 return err;2249 }2250 2251 soctherm_init(pdev);2252 2253 for (i = 0; i < soc->num_ttgs; ++i) {2254 struct thermal_zone_device *tz;2255 2256 tz = tegra->thermctl_tzs[soc->ttgs[i]->id];2257 err = tegra_soctherm_set_hwtrips(dev, soc->ttgs[i], tz);2258 if (err) {2259 dev_err(&pdev->dev,2260 "Resume failed: set hwtrips failed\n");2261 return err;2262 }2263 }2264 2265 return 0;2266}2267 2268static SIMPLE_DEV_PM_OPS(tegra_soctherm_pm, soctherm_suspend, soctherm_resume);2269 2270static struct platform_driver tegra_soctherm_driver = {2271 .probe = tegra_soctherm_probe,2272 .remove_new = tegra_soctherm_remove,2273 .driver = {2274 .name = "tegra_soctherm",2275 .pm = &tegra_soctherm_pm,2276 .of_match_table = tegra_soctherm_of_match,2277 },2278};2279module_platform_driver(tegra_soctherm_driver);2280 2281MODULE_AUTHOR("Mikko Perttunen <mperttunen@nvidia.com>");2282MODULE_DESCRIPTION("NVIDIA Tegra SOCTHERM thermal management driver");2283MODULE_LICENSE("GPL v2");2284