Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

thermal: tegra: add hw-throttle function

Tegra soctherm support HW throttle, when the soctherm snesors'
temperature is above the throttle trip point, it will trigger
pulse skiper to tune clocks accroding to the throttle depth.
Add this function for Tegra124 and Tegra210.
Since Tegra132 use different registers to configure pulse skiper,
will support it in next patch.

Signed-off-by: Wei Ni <wni@nvidia.com>
Signed-off-by: Zhang Rui <rui.zhang@intel.com>

authored by

Wei Ni and committed by
Zhang Rui
ce0dbf04 44f3d417

+700 -15
+653 -15
drivers/thermal/tegra/soctherm.c
··· 30 30 31 31 #include <dt-bindings/thermal/tegra124-soctherm.h> 32 32 33 + #include "../thermal_core.h" 33 34 #include "soctherm.h" 34 35 35 36 #define SENSOR_CONFIG0 0 ··· 68 67 #define READBACK_ADD_HALF BIT(7) 69 68 #define READBACK_NEGATE BIT(0) 70 69 70 + /* 71 + * THERMCTL_LEVEL0_GROUP_CPU is defined in soctherm.h 72 + * because it will be used by tegraxxx_soctherm.c 73 + */ 74 + #define THERMCTL_LVL0_CPU0_EN_MASK BIT(8) 75 + #define THERMCTL_LVL0_CPU0_CPU_THROT_MASK (0x3 << 5) 76 + #define THERMCTL_LVL0_CPU0_CPU_THROT_LIGHT 0x1 77 + #define THERMCTL_LVL0_CPU0_CPU_THROT_HEAVY 0x2 78 + #define THERMCTL_LVL0_CPU0_GPU_THROT_MASK (0x3 << 3) 79 + #define THERMCTL_LVL0_CPU0_GPU_THROT_LIGHT 0x1 80 + #define THERMCTL_LVL0_CPU0_GPU_THROT_HEAVY 0x2 81 + #define THERMCTL_LVL0_CPU0_MEM_THROT_MASK BIT(2) 82 + #define THERMCTL_LVL0_CPU0_STATUS_MASK 0x3 83 + 84 + #define THERMCTL_LVL0_UP_STATS 0x10 85 + #define THERMCTL_LVL0_DN_STATS 0x14 86 + 87 + #define THERMCTL_STATS_CTL 0x94 88 + #define STATS_CTL_CLR_DN 0x8 89 + #define STATS_CTL_EN_DN 0x4 90 + #define STATS_CTL_CLR_UP 0x2 91 + #define STATS_CTL_EN_UP 0x1 92 + 93 + #define THROT_GLOBAL_CFG 0x400 94 + #define THROT_GLOBAL_ENB_MASK BIT(0) 95 + 96 + #define CPU_PSKIP_STATUS 0x418 97 + #define XPU_PSKIP_STATUS_M_MASK (0xff << 12) 98 + #define XPU_PSKIP_STATUS_N_MASK (0xff << 4) 99 + #define XPU_PSKIP_STATUS_SW_OVERRIDE_MASK BIT(1) 100 + #define XPU_PSKIP_STATUS_ENABLED_MASK BIT(0) 101 + 102 + #define THROT_PRIORITY_LOCK 0x424 103 + #define THROT_PRIORITY_LOCK_PRIORITY_MASK 0xff 104 + 105 + #define THROT_STATUS 0x428 106 + #define THROT_STATUS_BREACH_MASK BIT(12) 107 + #define THROT_STATUS_STATE_MASK (0xff << 4) 108 + #define THROT_STATUS_ENABLED_MASK BIT(0) 109 + 110 + #define THROT_PSKIP_CTRL_LITE_CPU 0x430 111 + #define THROT_PSKIP_CTRL_ENABLE_MASK BIT(31) 112 + #define THROT_PSKIP_CTRL_DIVIDEND_MASK (0xff << 8) 113 + #define THROT_PSKIP_CTRL_DIVISOR_MASK 0xff 114 + #define THROT_PSKIP_CTRL_VECT_GPU_MASK (0x7 << 16) 115 + #define THROT_PSKIP_CTRL_VECT_CPU_MASK (0x7 << 8) 116 + #define THROT_PSKIP_CTRL_VECT2_CPU_MASK 0x7 117 + 118 + #define THROT_VECT_NONE 0x0 /* 3'b000 */ 119 + #define THROT_VECT_LOW 0x1 /* 3'b001 */ 120 + #define THROT_VECT_MED 0x3 /* 3'b011 */ 121 + #define THROT_VECT_HIGH 0x7 /* 3'b111 */ 122 + 123 + #define THROT_PSKIP_RAMP_LITE_CPU 0x434 124 + #define THROT_PSKIP_RAMP_SEQ_BYPASS_MODE_MASK BIT(31) 125 + #define THROT_PSKIP_RAMP_DURATION_MASK (0xffff << 8) 126 + #define THROT_PSKIP_RAMP_STEP_MASK 0xff 127 + 128 + #define THROT_PRIORITY_LITE 0x444 129 + #define THROT_PRIORITY_LITE_PRIO_MASK 0xff 130 + 131 + #define THROT_DELAY_LITE 0x448 132 + #define THROT_DELAY_LITE_DELAY_MASK 0xff 133 + 134 + /* car register offsets needed for enabling HW throttling */ 135 + #define CAR_SUPER_CCLKG_DIVIDER 0x36c 136 + #define CDIVG_USE_THERM_CONTROLS_MASK BIT(30) 137 + 71 138 /* get val from register(r) mask bits(m) */ 72 139 #define REG_GET_MASK(r, m) (((r) & (m)) >> (ffs(m) - 1)) 73 140 /* set val(v) to mask bits(m) of register(r) */ 74 141 #define REG_SET_MASK(r, m, v) (((r) & ~(m)) | \ 75 142 (((v) & (m >> (ffs(m) - 1))) << (ffs(m) - 1))) 76 143 144 + /* get dividend from the depth */ 145 + #define THROT_DEPTH_DIVIDEND(depth) ((256 * (100 - (depth)) / 100) - 1) 146 + 147 + /* get THROT_PSKIP_xxx offset per LIGHT/HEAVY throt and CPU/GPU dev */ 148 + #define THROT_OFFSET 0x30 149 + #define THROT_PSKIP_CTRL(throt, dev) (THROT_PSKIP_CTRL_LITE_CPU + \ 150 + (THROT_OFFSET * throt) + (8 * dev)) 151 + #define THROT_PSKIP_RAMP(throt, dev) (THROT_PSKIP_RAMP_LITE_CPU + \ 152 + (THROT_OFFSET * throt) + (8 * dev)) 153 + 154 + /* get THROT_xxx_CTRL offset per LIGHT/HEAVY throt */ 155 + #define THROT_PRIORITY_CTRL(throt) (THROT_PRIORITY_LITE + \ 156 + (THROT_OFFSET * throt)) 157 + #define THROT_DELAY_CTRL(throt) (THROT_DELAY_LITE + \ 158 + (THROT_OFFSET * throt)) 159 + 160 + /* get THERMCTL_LEVELx offset per CPU/GPU/MEM/TSENSE rg and LEVEL0~3 lv */ 161 + #define THERMCTL_LVL_REGS_SIZE 0x20 162 + #define THERMCTL_LVL_REG(rg, lv) ((rg) + ((lv) * THERMCTL_LVL_REGS_SIZE)) 163 + 77 164 static const int min_low_temp = -127000; 78 165 static const int max_high_temp = 127000; 79 166 167 + enum soctherm_throttle_id { 168 + THROTTLE_LIGHT = 0, 169 + THROTTLE_HEAVY, 170 + THROTTLE_SIZE, 171 + }; 172 + 173 + enum soctherm_throttle_dev_id { 174 + THROTTLE_DEV_CPU = 0, 175 + THROTTLE_DEV_GPU, 176 + THROTTLE_DEV_SIZE, 177 + }; 178 + 179 + static const char *const throt_names[] = { 180 + [THROTTLE_LIGHT] = "light", 181 + [THROTTLE_HEAVY] = "heavy", 182 + }; 183 + 184 + struct tegra_soctherm; 80 185 struct tegra_thermctl_zone { 81 186 void __iomem *reg; 82 187 struct device *dev; 188 + struct tegra_soctherm *ts; 83 189 struct thermal_zone_device *tz; 84 190 const struct tegra_tsensor_group *sg; 191 + }; 192 + 193 + struct soctherm_throt_cfg { 194 + const char *name; 195 + unsigned int id; 196 + u8 priority; 197 + u32 cpu_throt_depth; 198 + struct thermal_cooling_device *cdev; 199 + bool init; 85 200 }; 86 201 87 202 struct tegra_soctherm { ··· 205 88 struct clk *clock_tsensor; 206 89 struct clk *clock_soctherm; 207 90 void __iomem *regs; 208 - struct thermal_zone_device **thermctl_tzs; 91 + void __iomem *clk_regs; 209 92 210 93 u32 *calib; 94 + struct thermal_zone_device **thermctl_tzs; 211 95 struct tegra_soctherm_soc *soc; 96 + 97 + struct soctherm_throt_cfg throt_cfgs[THROTTLE_SIZE]; 212 98 213 99 struct dentry *debugfs_dir; 214 100 }; 101 + 102 + /** 103 + * clk_writel() - writes a value to a CAR register 104 + * @ts: pointer to a struct tegra_soctherm 105 + * @v: the value to write 106 + * @reg: the register offset 107 + * 108 + * Writes @v to @reg. No return value. 109 + */ 110 + static inline void clk_writel(struct tegra_soctherm *ts, u32 value, u32 reg) 111 + { 112 + writel(value, (ts->clk_regs + reg)); 113 + } 114 + 115 + /** 116 + * clk_readl() - reads specified register from CAR IP block 117 + * @ts: pointer to a struct tegra_soctherm 118 + * @reg: register address to be read 119 + * 120 + * Return: the value of the register 121 + */ 122 + static inline u32 clk_readl(struct tegra_soctherm *ts, u32 reg) 123 + { 124 + return readl(ts->clk_regs + reg); 125 + } 215 126 216 127 static void enable_tsensor(struct tegra_soctherm *tegra, unsigned int i) 217 128 { ··· 295 150 static int 296 151 thermtrip_program(struct device *dev, const struct tegra_tsensor_group *sg, 297 152 int trip_temp); 153 + static int 154 + throttrip_program(struct device *dev, const struct tegra_tsensor_group *sg, 155 + struct soctherm_throt_cfg *stc, int trip_temp); 156 + static struct soctherm_throt_cfg * 157 + find_throttle_cfg_by_name(struct tegra_soctherm *ts, const char *name); 298 158 299 159 static int tegra_thermctl_set_trip_temp(void *data, int trip, int temp) 300 160 { 301 161 struct tegra_thermctl_zone *zone = data; 302 162 struct thermal_zone_device *tz = zone->tz; 163 + struct tegra_soctherm *ts = zone->ts; 303 164 const struct tegra_tsensor_group *sg = zone->sg; 304 165 struct device *dev = zone->dev; 305 166 enum thermal_trip_type type; ··· 318 167 if (ret) 319 168 return ret; 320 169 321 - if (type != THERMAL_TRIP_CRITICAL) 322 - return 0; 170 + if (type == THERMAL_TRIP_CRITICAL) { 171 + return thermtrip_program(dev, sg, temp); 172 + } else if (type == THERMAL_TRIP_HOT) { 173 + int i; 323 174 324 - return thermtrip_program(dev, sg, temp); 175 + for (i = 0; i < THROTTLE_SIZE; i++) { 176 + struct thermal_cooling_device *cdev; 177 + struct soctherm_throt_cfg *stc; 178 + 179 + if (!ts->throt_cfgs[i].init) 180 + continue; 181 + 182 + cdev = ts->throt_cfgs[i].cdev; 183 + if (get_thermal_instance(tz, cdev, trip)) 184 + stc = find_throttle_cfg_by_name(ts, cdev->type); 185 + else 186 + continue; 187 + 188 + return throttrip_program(dev, sg, stc, temp); 189 + } 190 + } 191 + 192 + return 0; 325 193 } 326 194 327 195 static const struct thermal_zone_of_device_ops tegra_of_thermal_ops = { ··· 408 238 } 409 239 410 240 /** 241 + * throttrip_program() - Configures the hardware to throttle the 242 + * pulse if a given sensor group reaches a given temperature 243 + * @dev: ptr to the struct device for the SOC_THERM IP block 244 + * @sg: pointer to the sensor group to set the thermtrip temperature for 245 + * @stc: pointer to the throttle need to be triggered 246 + * @trip_temp: the temperature in millicelsius to trigger the thermal trip at 247 + * 248 + * Sets the thermal trip threshold and throttle event of the given sensor 249 + * group. If this threshold is crossed, the hardware will trigger the 250 + * throttle. 251 + * 252 + * Note that, although @trip_temp is specified in millicelsius, the 253 + * hardware is programmed in degrees Celsius. 254 + * 255 + * Return: 0 upon success, or %-EINVAL upon failure. 256 + */ 257 + static int throttrip_program(struct device *dev, 258 + const struct tegra_tsensor_group *sg, 259 + struct soctherm_throt_cfg *stc, 260 + int trip_temp) 261 + { 262 + struct tegra_soctherm *ts = dev_get_drvdata(dev); 263 + int temp, cpu_throt, gpu_throt; 264 + unsigned int throt; 265 + u32 r, reg_off; 266 + 267 + if (!dev || !sg || !stc || !stc->init) 268 + return -EINVAL; 269 + 270 + temp = enforce_temp_range(dev, trip_temp) / ts->soc->thresh_grain; 271 + 272 + /* Hardcode LIGHT on LEVEL1 and HEAVY on LEVEL2 */ 273 + throt = stc->id; 274 + reg_off = THERMCTL_LVL_REG(sg->thermctl_lvl0_offset, throt + 1); 275 + 276 + if (throt == THROTTLE_LIGHT) { 277 + cpu_throt = THERMCTL_LVL0_CPU0_CPU_THROT_LIGHT; 278 + gpu_throt = THERMCTL_LVL0_CPU0_GPU_THROT_LIGHT; 279 + } else { 280 + cpu_throt = THERMCTL_LVL0_CPU0_CPU_THROT_HEAVY; 281 + gpu_throt = THERMCTL_LVL0_CPU0_GPU_THROT_HEAVY; 282 + if (throt != THROTTLE_HEAVY) 283 + dev_warn(dev, 284 + "invalid throt id %d - assuming HEAVY", 285 + throt); 286 + } 287 + 288 + r = readl(ts->regs + reg_off); 289 + r = REG_SET_MASK(r, sg->thermctl_lvl0_up_thresh_mask, temp); 290 + r = REG_SET_MASK(r, sg->thermctl_lvl0_dn_thresh_mask, temp); 291 + r = REG_SET_MASK(r, THERMCTL_LVL0_CPU0_CPU_THROT_MASK, cpu_throt); 292 + r = REG_SET_MASK(r, THERMCTL_LVL0_CPU0_GPU_THROT_MASK, gpu_throt); 293 + r = REG_SET_MASK(r, THERMCTL_LVL0_CPU0_EN_MASK, 1); 294 + writel(r, ts->regs + reg_off); 295 + 296 + return 0; 297 + } 298 + 299 + static struct soctherm_throt_cfg * 300 + find_throttle_cfg_by_name(struct tegra_soctherm *ts, const char *name) 301 + { 302 + unsigned int i; 303 + 304 + for (i = 0; ts->throt_cfgs[i].name; i++) 305 + if (!strcmp(ts->throt_cfgs[i].name, name)) 306 + return &ts->throt_cfgs[i]; 307 + 308 + return NULL; 309 + } 310 + 311 + static int get_hot_temp(struct thermal_zone_device *tz, int *trip, int *temp) 312 + { 313 + int ntrips, i, ret; 314 + enum thermal_trip_type type; 315 + 316 + ntrips = of_thermal_get_ntrips(tz); 317 + if (ntrips <= 0) 318 + return -EINVAL; 319 + 320 + for (i = 0; i < ntrips; i++) { 321 + ret = tz->ops->get_trip_type(tz, i, &type); 322 + if (ret) 323 + return -EINVAL; 324 + if (type == THERMAL_TRIP_HOT) { 325 + ret = tz->ops->get_trip_temp(tz, i, temp); 326 + if (!ret) 327 + *trip = i; 328 + 329 + return ret; 330 + } 331 + } 332 + 333 + return -EINVAL; 334 + } 335 + 336 + /** 411 337 * tegra_soctherm_set_hwtrips() - set HW trip point from DT data 412 338 * @dev: struct device * of the SOC_THERM instance 413 339 * 414 340 * Configure the SOC_THERM HW trip points, setting "THERMTRIP" 415 - * trip points , using "critical" type trip_temp from thermal 416 - * zone. 417 - * After they have been configured, THERMTRIP will take action 418 - * when the configured SoC thermal sensor group reaches a 341 + * "THROTTLE" trip points , using "critical" or "hot" type trip_temp 342 + * from thermal zone. 343 + * After they have been configured, THERMTRIP or THROTTLE will take 344 + * action when the configured SoC thermal sensor group reaches a 419 345 * certain temperature. 420 346 * 421 347 * Return: 0 upon success, or a negative error code on failure. ··· 520 254 * THERMTRIP has been enabled successfully when a message similar to 521 255 * this one appears on the serial console: 522 256 * "thermtrip: will shut down when sensor group XXX reaches YYYYYY mC" 257 + * THROTTLE has been enabled successfully when a message similar to 258 + * this one appears on the serial console: 259 + * ""throttrip: will throttle when sensor group XXX reaches YYYYYY mC" 523 260 */ 524 261 static int tegra_soctherm_set_hwtrips(struct device *dev, 525 262 const struct tegra_tsensor_group *sg, 526 263 struct thermal_zone_device *tz) 527 264 { 528 - int temperature; 265 + struct tegra_soctherm *ts = dev_get_drvdata(dev); 266 + struct soctherm_throt_cfg *stc; 267 + int i, trip, temperature; 529 268 int ret; 530 269 531 270 ret = tz->ops->get_crit_temp(tz, &temperature); 532 271 if (ret) { 533 272 dev_warn(dev, "thermtrip: %s: missing critical temperature\n", 534 273 sg->name); 535 - return ret; 274 + goto set_throttle; 536 275 } 537 276 538 277 ret = thermtrip_program(dev, sg, temperature); ··· 551 280 "thermtrip: will shut down when %s reaches %d mC\n", 552 281 sg->name, temperature); 553 282 283 + set_throttle: 284 + if (ts->soc->use_ccroc) 285 + return 0; 286 + 287 + ret = get_hot_temp(tz, &trip, &temperature); 288 + if (ret) { 289 + dev_warn(dev, "throttrip: %s: missing hot temperature\n", 290 + sg->name); 291 + return 0; 292 + } 293 + 294 + for (i = 0; i < THROTTLE_SIZE; i++) { 295 + struct thermal_cooling_device *cdev; 296 + 297 + if (!ts->throt_cfgs[i].init) 298 + continue; 299 + 300 + cdev = ts->throt_cfgs[i].cdev; 301 + if (get_thermal_instance(tz, cdev, trip)) 302 + stc = find_throttle_cfg_by_name(ts, cdev->type); 303 + else 304 + continue; 305 + 306 + ret = throttrip_program(dev, sg, stc, temperature); 307 + if (ret) { 308 + dev_err(dev, "throttrip: %s: error during enable\n", 309 + sg->name); 310 + return ret; 311 + } 312 + 313 + dev_info(dev, 314 + "throttrip: will throttle when %s reaches %d mC\n", 315 + sg->name, temperature); 316 + break; 317 + } 318 + 319 + if (i == THROTTLE_SIZE) 320 + dev_warn(dev, "throttrip: %s: missing throttle cdev\n", 321 + sg->name); 322 + 554 323 return 0; 555 324 } 556 325 ··· 602 291 const struct tegra_tsensor *tsensors = ts->soc->tsensors; 603 292 const struct tegra_tsensor_group **ttgs = ts->soc->ttgs; 604 293 u32 r, state; 605 - int i; 294 + int i, level; 606 295 607 296 seq_puts(s, "-----TSENSE (convert HW)-----\n"); 608 297 ··· 676 365 state = REG_GET_MASK(r, SENSOR_TEMP2_MEM_TEMP_MASK); 677 366 seq_printf(s, " MEM(%d)\n", translate_temp(state)); 678 367 368 + if (ts->soc->use_ccroc) 369 + return 0; 370 + 371 + for (i = 0; i < ts->soc->num_ttgs; i++) { 372 + seq_printf(s, "%s:\n", ttgs[i]->name); 373 + for (level = 0; level < 4; level++) { 374 + s32 v; 375 + u32 mask; 376 + u16 off = ttgs[i]->thermctl_lvl0_offset; 377 + 378 + r = readl(ts->regs + THERMCTL_LVL_REG(off, level)); 379 + 380 + mask = ttgs[i]->thermctl_lvl0_up_thresh_mask; 381 + state = REG_GET_MASK(r, mask); 382 + v = sign_extend32(state, ts->soc->bptt - 1); 383 + v *= ts->soc->thresh_grain; 384 + seq_printf(s, " %d: Up/Dn(%d /", level, v); 385 + 386 + mask = ttgs[i]->thermctl_lvl0_dn_thresh_mask; 387 + state = REG_GET_MASK(r, mask); 388 + v = sign_extend32(state, ts->soc->bptt - 1); 389 + v *= ts->soc->thresh_grain; 390 + seq_printf(s, "%d ) ", v); 391 + 392 + mask = THERMCTL_LVL0_CPU0_EN_MASK; 393 + state = REG_GET_MASK(r, mask); 394 + seq_printf(s, "En(%d) ", state); 395 + 396 + mask = THERMCTL_LVL0_CPU0_CPU_THROT_MASK; 397 + state = REG_GET_MASK(r, mask); 398 + seq_puts(s, "CPU Throt"); 399 + if (!state) 400 + seq_printf(s, "(%s) ", "none"); 401 + else if (state == THERMCTL_LVL0_CPU0_CPU_THROT_LIGHT) 402 + seq_printf(s, "(%s) ", "L"); 403 + else if (state == THERMCTL_LVL0_CPU0_CPU_THROT_HEAVY) 404 + seq_printf(s, "(%s) ", "H"); 405 + else 406 + seq_printf(s, "(%s) ", "H+L"); 407 + 408 + mask = THERMCTL_LVL0_CPU0_GPU_THROT_MASK; 409 + state = REG_GET_MASK(r, mask); 410 + seq_puts(s, "GPU Throt"); 411 + if (!state) 412 + seq_printf(s, "(%s) ", "none"); 413 + else if (state == THERMCTL_LVL0_CPU0_GPU_THROT_LIGHT) 414 + seq_printf(s, "(%s) ", "L"); 415 + else if (state == THERMCTL_LVL0_CPU0_GPU_THROT_HEAVY) 416 + seq_printf(s, "(%s) ", "H"); 417 + else 418 + seq_printf(s, "(%s) ", "H+L"); 419 + 420 + mask = THERMCTL_LVL0_CPU0_STATUS_MASK; 421 + state = REG_GET_MASK(r, mask); 422 + seq_printf(s, "Status(%s)\n", 423 + state == 0 ? "LO" : 424 + state == 1 ? "In" : 425 + state == 2 ? "Res" : "HI"); 426 + } 427 + } 428 + 429 + r = readl(ts->regs + THERMCTL_STATS_CTL); 430 + seq_printf(s, "STATS: Up(%s) Dn(%s)\n", 431 + r & STATS_CTL_EN_UP ? "En" : "--", 432 + r & STATS_CTL_EN_DN ? "En" : "--"); 433 + 434 + for (level = 0; level < 4; level++) { 435 + u16 off; 436 + 437 + off = THERMCTL_LVL0_UP_STATS; 438 + r = readl(ts->regs + THERMCTL_LVL_REG(off, level)); 439 + seq_printf(s, " Level_%d Up(%d) ", level, r); 440 + 441 + off = THERMCTL_LVL0_DN_STATS; 442 + r = readl(ts->regs + THERMCTL_LVL_REG(off, level)); 443 + seq_printf(s, "Dn(%d)\n", r); 444 + } 445 + 679 446 r = readl(ts->regs + THERMCTL_THERMTRIP_CTL); 680 447 state = REG_GET_MASK(r, ttgs[0]->thermtrip_any_en_mask); 681 448 seq_printf(s, "Thermtrip Any En(%d)\n", state); ··· 764 375 state *= ts->soc->thresh_grain; 765 376 seq_printf(s, "Thresh(%d)\n", state); 766 377 } 378 + 379 + r = readl(ts->regs + THROT_GLOBAL_CFG); 380 + seq_puts(s, "\n"); 381 + seq_printf(s, "GLOBAL THROTTLE CONFIG: 0x%08x\n", r); 382 + 383 + seq_puts(s, "---------------------------------------------------\n"); 384 + r = readl(ts->regs + THROT_STATUS); 385 + state = REG_GET_MASK(r, THROT_STATUS_BREACH_MASK); 386 + seq_printf(s, "THROT STATUS: breach(%d) ", state); 387 + state = REG_GET_MASK(r, THROT_STATUS_STATE_MASK); 388 + seq_printf(s, "state(%d) ", state); 389 + state = REG_GET_MASK(r, THROT_STATUS_ENABLED_MASK); 390 + seq_printf(s, "enabled(%d)\n", state); 391 + 392 + r = readl(ts->regs + CPU_PSKIP_STATUS); 393 + state = REG_GET_MASK(r, XPU_PSKIP_STATUS_M_MASK); 394 + seq_printf(s, "CPU PSKIP STATUS: M(%d) ", state); 395 + state = REG_GET_MASK(r, XPU_PSKIP_STATUS_N_MASK); 396 + seq_printf(s, "N(%d) ", state); 397 + state = REG_GET_MASK(r, XPU_PSKIP_STATUS_ENABLED_MASK); 398 + seq_printf(s, "enabled(%d)\n", state); 767 399 768 400 return 0; 769 401 } ··· 859 449 return 0; 860 450 } 861 451 452 + static int throt_get_cdev_max_state(struct thermal_cooling_device *cdev, 453 + unsigned long *max_state) 454 + { 455 + *max_state = 1; 456 + return 0; 457 + } 458 + 459 + static int throt_get_cdev_cur_state(struct thermal_cooling_device *cdev, 460 + unsigned long *cur_state) 461 + { 462 + struct tegra_soctherm *ts = cdev->devdata; 463 + u32 r; 464 + 465 + r = readl(ts->regs + THROT_STATUS); 466 + if (REG_GET_MASK(r, THROT_STATUS_STATE_MASK)) 467 + *cur_state = 1; 468 + else 469 + *cur_state = 0; 470 + 471 + return 0; 472 + } 473 + 474 + static int throt_set_cdev_state(struct thermal_cooling_device *cdev, 475 + unsigned long cur_state) 476 + { 477 + return 0; 478 + } 479 + 480 + static struct thermal_cooling_device_ops throt_cooling_ops = { 481 + .get_max_state = throt_get_cdev_max_state, 482 + .get_cur_state = throt_get_cdev_cur_state, 483 + .set_cur_state = throt_set_cdev_state, 484 + }; 485 + 486 + /** 487 + * soctherm_init_hw_throt_cdev() - Parse the HW throttle configurations 488 + * and register them as cooling devices. 489 + */ 490 + static void soctherm_init_hw_throt_cdev(struct platform_device *pdev) 491 + { 492 + struct device *dev = &pdev->dev; 493 + struct tegra_soctherm *ts = dev_get_drvdata(dev); 494 + struct device_node *np_stc, *np_stcc; 495 + const char *name; 496 + u32 val; 497 + int i, r; 498 + 499 + for (i = 0; i < THROTTLE_SIZE; i++) { 500 + ts->throt_cfgs[i].name = throt_names[i]; 501 + ts->throt_cfgs[i].id = i; 502 + ts->throt_cfgs[i].init = false; 503 + } 504 + 505 + np_stc = of_get_child_by_name(dev->of_node, "throttle-cfgs"); 506 + if (!np_stc) { 507 + dev_info(dev, 508 + "throttle-cfg: no throttle-cfgs - not enabling\n"); 509 + return; 510 + } 511 + 512 + for_each_child_of_node(np_stc, np_stcc) { 513 + struct soctherm_throt_cfg *stc; 514 + struct thermal_cooling_device *tcd; 515 + 516 + name = np_stcc->name; 517 + stc = find_throttle_cfg_by_name(ts, name); 518 + if (!stc) { 519 + dev_err(dev, 520 + "throttle-cfg: could not find %s\n", name); 521 + continue; 522 + } 523 + 524 + r = of_property_read_u32(np_stcc, "nvidia,priority", &val); 525 + if (r) { 526 + dev_info(dev, 527 + "throttle-cfg: %s: missing priority\n", name); 528 + continue; 529 + } 530 + stc->priority = val; 531 + 532 + r = of_property_read_u32(np_stcc, "nvidia,cpu-throt-percent", 533 + &val); 534 + if (r) { 535 + dev_info(dev, 536 + "throttle-cfg: %s: missing cpu-throt-percent\n", 537 + name); 538 + continue; 539 + } 540 + stc->cpu_throt_depth = val; 541 + 542 + tcd = thermal_of_cooling_device_register(np_stcc, 543 + (char *)name, ts, 544 + &throt_cooling_ops); 545 + of_node_put(np_stcc); 546 + if (IS_ERR_OR_NULL(tcd)) { 547 + dev_err(dev, 548 + "throttle-cfg: %s: failed to register cooling device\n", 549 + name); 550 + continue; 551 + } 552 + 553 + stc->cdev = tcd; 554 + stc->init = true; 555 + } 556 + 557 + of_node_put(np_stc); 558 + } 559 + 560 + /** 561 + * throttlectl_cpu_mn() - program CPU pulse skipper configuration 562 + * @throt: the LIGHT/HEAVY of throttle event id 563 + * 564 + * Pulse skippers are used to throttle clock frequencies. This 565 + * function programs the pulse skippers based on @throt and platform 566 + * data. This function is used for CPUs that have "remote" pulse 567 + * skipper control, e.g., the CPU pulse skipper is controlled by the 568 + * SOC_THERM IP block. (SOC_THERM is located outside the CPU 569 + * complex.) 570 + */ 571 + static void throttlectl_cpu_mn(struct tegra_soctherm *ts, 572 + enum soctherm_throttle_id throt) 573 + { 574 + u32 r; 575 + int depth; 576 + u8 dividend; 577 + 578 + depth = ts->throt_cfgs[throt].cpu_throt_depth; 579 + dividend = THROT_DEPTH_DIVIDEND(depth); 580 + 581 + r = readl(ts->regs + THROT_PSKIP_CTRL(throt, THROTTLE_DEV_CPU)); 582 + r = REG_SET_MASK(r, THROT_PSKIP_CTRL_ENABLE_MASK, 1); 583 + r = REG_SET_MASK(r, THROT_PSKIP_CTRL_DIVIDEND_MASK, dividend); 584 + r = REG_SET_MASK(r, THROT_PSKIP_CTRL_DIVISOR_MASK, 0xff); 585 + writel(r, ts->regs + THROT_PSKIP_CTRL(throt, THROTTLE_DEV_CPU)); 586 + 587 + r = readl(ts->regs + THROT_PSKIP_RAMP(throt, THROTTLE_DEV_CPU)); 588 + r = REG_SET_MASK(r, THROT_PSKIP_RAMP_DURATION_MASK, 0xff); 589 + r = REG_SET_MASK(r, THROT_PSKIP_RAMP_STEP_MASK, 0xf); 590 + writel(r, ts->regs + THROT_PSKIP_RAMP(throt, THROTTLE_DEV_CPU)); 591 + } 592 + 593 + /** 594 + * soctherm_throttle_program() - programs pulse skippers' configuration 595 + * @throt: the LIGHT/HEAVY of the throttle event id. 596 + * 597 + * Pulse skippers are used to throttle clock frequencies. 598 + * This function programs the pulse skippers. 599 + */ 600 + static void soctherm_throttle_program(struct tegra_soctherm *ts, 601 + enum soctherm_throttle_id throt) 602 + { 603 + u32 r; 604 + struct soctherm_throt_cfg stc = ts->throt_cfgs[throt]; 605 + 606 + if (!stc.init) 607 + return; 608 + 609 + /* Setup PSKIP parameters */ 610 + throttlectl_cpu_mn(ts, throt); 611 + 612 + r = REG_SET_MASK(0, THROT_PRIORITY_LITE_PRIO_MASK, stc.priority); 613 + writel(r, ts->regs + THROT_PRIORITY_CTRL(throt)); 614 + 615 + r = REG_SET_MASK(0, THROT_DELAY_LITE_DELAY_MASK, 0); 616 + writel(r, ts->regs + THROT_DELAY_CTRL(throt)); 617 + 618 + r = readl(ts->regs + THROT_PRIORITY_LOCK); 619 + r = REG_GET_MASK(r, THROT_PRIORITY_LOCK_PRIORITY_MASK); 620 + if (r >= stc.priority) 621 + return; 622 + r = REG_SET_MASK(0, THROT_PRIORITY_LOCK_PRIORITY_MASK, 623 + stc.priority); 624 + writel(r, ts->regs + THROT_PRIORITY_LOCK); 625 + } 626 + 627 + static void tegra_soctherm_throttle(struct device *dev) 628 + { 629 + struct tegra_soctherm *ts = dev_get_drvdata(dev); 630 + u32 v; 631 + int i; 632 + 633 + /* Thermal HW throttle programming */ 634 + for (i = 0; i < THROTTLE_SIZE; i++) 635 + soctherm_throttle_program(ts, i); 636 + 637 + v = REG_SET_MASK(0, THROT_GLOBAL_ENB_MASK, 1); 638 + writel(v, ts->regs + THROT_GLOBAL_CFG); 639 + 640 + v = clk_readl(ts, CAR_SUPER_CCLKG_DIVIDER); 641 + v = REG_SET_MASK(v, CDIVG_USE_THERM_CONTROLS_MASK, 1); 642 + clk_writel(ts, v, CAR_SUPER_CCLKG_DIVIDER); 643 + 644 + /* initialize stats collection */ 645 + v = STATS_CTL_CLR_DN | STATS_CTL_EN_DN | 646 + STATS_CTL_CLR_UP | STATS_CTL_EN_UP; 647 + writel(v, ts->regs + THERMCTL_STATS_CTL); 648 + } 649 + 862 650 static void soctherm_init(struct platform_device *pdev) 863 651 { 864 652 struct tegra_soctherm *tegra = platform_get_drvdata(pdev); ··· 1083 475 } 1084 476 writel(pdiv, tegra->regs + SENSOR_PDIV); 1085 477 writel(hotspot, tegra->regs + SENSOR_HOTSPOT_OFF); 478 + 479 + if (tegra->soc->use_ccroc) 480 + return; 481 + 482 + /* Configure hw throttle */ 483 + tegra_soctherm_throttle(&pdev->dev); 1086 484 } 1087 485 1088 486 static const struct of_device_id tegra_soctherm_of_match[] = { ··· 1141 527 1142 528 tegra->soc = soc; 1143 529 1144 - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 530 + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, 531 + "soctherm-reg"); 1145 532 tegra->regs = devm_ioremap_resource(&pdev->dev, res); 1146 - if (IS_ERR(tegra->regs)) 533 + if (IS_ERR(tegra->regs)) { 534 + dev_err(&pdev->dev, "can't get soctherm registers"); 1147 535 return PTR_ERR(tegra->regs); 536 + } 537 + 538 + if (!tegra->soc->use_ccroc) { 539 + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, 540 + "car-reg"); 541 + tegra->clk_regs = devm_ioremap_resource(&pdev->dev, res); 542 + if (IS_ERR(tegra->clk_regs)) { 543 + dev_err(&pdev->dev, "can't get car clk registers"); 544 + return PTR_ERR(tegra->clk_regs); 545 + } 546 + } 1148 547 1149 548 tegra->reset = devm_reset_control_get(&pdev->dev, "soctherm"); 1150 549 if (IS_ERR(tegra->reset)) { ··· 1207 580 if (err) 1208 581 return err; 1209 582 583 + if (!tegra->soc->use_ccroc) 584 + soctherm_init_hw_throt_cdev(pdev); 585 + 1210 586 soctherm_init(pdev); 1211 587 1212 588 for (i = 0; i < soc->num_ttgs; ++i) { ··· 1223 593 zone->reg = tegra->regs + soc->ttgs[i]->sensor_temp_offset; 1224 594 zone->dev = &pdev->dev; 1225 595 zone->sg = soc->ttgs[i]; 596 + zone->ts = tegra; 1226 597 1227 598 z = devm_thermal_zone_of_sensor_register(&pdev->dev, 1228 599 soc->ttgs[i]->id, zone, ··· 1239 608 tegra->thermctl_tzs[soc->ttgs[i]->id] = z; 1240 609 1241 610 /* Configure hw trip points */ 1242 - tegra_soctherm_set_hwtrips(&pdev->dev, soc->ttgs[i], z); 611 + err = tegra_soctherm_set_hwtrips(&pdev->dev, soc->ttgs[i], z); 612 + if (err) 613 + goto disable_clocks; 1243 614 } 1244 615 1245 616 soctherm_debug_init(pdev); ··· 1294 661 struct thermal_zone_device *tz; 1295 662 1296 663 tz = tegra->thermctl_tzs[soc->ttgs[i]->id]; 1297 - tegra_soctherm_set_hwtrips(dev, soc->ttgs[i], tz); 664 + err = tegra_soctherm_set_hwtrips(dev, soc->ttgs[i], tz); 665 + if (err) { 666 + dev_err(&pdev->dev, 667 + "Resume failed: set hwtrips failed\n"); 668 + return err; 669 + } 1298 670 } 1299 671 1300 672 return 0;
+10
drivers/thermal/tegra/soctherm.h
··· 15 15 #ifndef __DRIVERS_THERMAL_TEGRA_SOCTHERM_H 16 16 #define __DRIVERS_THERMAL_TEGRA_SOCTHERM_H 17 17 18 + #define THERMCTL_LEVEL0_GROUP_CPU 0x0 19 + #define THERMCTL_LEVEL0_GROUP_GPU 0x4 20 + #define THERMCTL_LEVEL0_GROUP_MEM 0x8 21 + #define THERMCTL_LEVEL0_GROUP_TSENSE 0xc 22 + 18 23 #define SENSOR_CONFIG2 8 19 24 #define SENSOR_CONFIG2_THERMA_MASK (0xffff << 16) 20 25 #define SENSOR_CONFIG2_THERMA_SHIFT 16 ··· 70 65 u32 thermtrip_enable_mask; 71 66 u32 thermtrip_any_en_mask; 72 67 u32 thermtrip_threshold_mask; 68 + u16 thermctl_lvl0_offset; 69 + u32 thermctl_lvl0_up_thresh_mask; 70 + u32 thermctl_lvl0_dn_thresh_mask; 73 71 }; 74 72 75 73 struct tegra_tsensor_configuration { ··· 111 103 const unsigned int num_ttgs; 112 104 const struct tegra_soctherm_fuse *tfuse; 113 105 const int thresh_grain; 106 + const unsigned int bptt; 107 + const bool use_ccroc; 114 108 }; 115 109 116 110 int tegra_calc_shared_calib(const struct tegra_soctherm_fuse *tfuse,
+18
drivers/thermal/tegra/tegra124-soctherm.c
··· 28 28 #define TEGRA124_THERMTRIP_CPU_THRESH_MASK (0xff << 8) 29 29 #define TEGRA124_THERMTRIP_TSENSE_THRESH_MASK 0xff 30 30 31 + #define TEGRA124_THERMCTL_LVL0_UP_THRESH_MASK (0xff << 17) 32 + #define TEGRA124_THERMCTL_LVL0_DN_THRESH_MASK (0xff << 9) 33 + 31 34 #define TEGRA124_THRESH_GRAIN 1000 35 + #define TEGRA124_BPTT 8 32 36 33 37 static const struct tegra_tsensor_configuration tegra124_tsensor_config = { 34 38 .tall = 16300, ··· 55 51 .thermtrip_any_en_mask = TEGRA124_THERMTRIP_ANY_EN_MASK, 56 52 .thermtrip_enable_mask = TEGRA124_THERMTRIP_CPU_EN_MASK, 57 53 .thermtrip_threshold_mask = TEGRA124_THERMTRIP_CPU_THRESH_MASK, 54 + .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_CPU, 55 + .thermctl_lvl0_up_thresh_mask = TEGRA124_THERMCTL_LVL0_UP_THRESH_MASK, 56 + .thermctl_lvl0_dn_thresh_mask = TEGRA124_THERMCTL_LVL0_DN_THRESH_MASK, 58 57 }; 59 58 60 59 static const struct tegra_tsensor_group tegra124_tsensor_group_gpu = { ··· 73 66 .thermtrip_any_en_mask = TEGRA124_THERMTRIP_ANY_EN_MASK, 74 67 .thermtrip_enable_mask = TEGRA124_THERMTRIP_GPU_EN_MASK, 75 68 .thermtrip_threshold_mask = TEGRA124_THERMTRIP_GPUMEM_THRESH_MASK, 69 + .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_GPU, 70 + .thermctl_lvl0_up_thresh_mask = TEGRA124_THERMCTL_LVL0_UP_THRESH_MASK, 71 + .thermctl_lvl0_dn_thresh_mask = TEGRA124_THERMCTL_LVL0_DN_THRESH_MASK, 76 72 }; 77 73 78 74 static const struct tegra_tsensor_group tegra124_tsensor_group_pll = { ··· 89 79 .thermtrip_any_en_mask = TEGRA124_THERMTRIP_ANY_EN_MASK, 90 80 .thermtrip_enable_mask = TEGRA124_THERMTRIP_TSENSE_EN_MASK, 91 81 .thermtrip_threshold_mask = TEGRA124_THERMTRIP_TSENSE_THRESH_MASK, 82 + .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_TSENSE, 83 + .thermctl_lvl0_up_thresh_mask = TEGRA124_THERMCTL_LVL0_UP_THRESH_MASK, 84 + .thermctl_lvl0_dn_thresh_mask = TEGRA124_THERMCTL_LVL0_DN_THRESH_MASK, 92 85 }; 93 86 94 87 static const struct tegra_tsensor_group tegra124_tsensor_group_mem = { ··· 107 94 .thermtrip_any_en_mask = TEGRA124_THERMTRIP_ANY_EN_MASK, 108 95 .thermtrip_enable_mask = TEGRA124_THERMTRIP_MEM_EN_MASK, 109 96 .thermtrip_threshold_mask = TEGRA124_THERMTRIP_GPUMEM_THRESH_MASK, 97 + .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_MEM, 98 + .thermctl_lvl0_up_thresh_mask = TEGRA124_THERMCTL_LVL0_UP_THRESH_MASK, 99 + .thermctl_lvl0_dn_thresh_mask = TEGRA124_THERMCTL_LVL0_DN_THRESH_MASK, 110 100 }; 111 101 112 102 static const struct tegra_tsensor_group *tegra124_tsensor_groups[] = { ··· 209 193 .num_ttgs = ARRAY_SIZE(tegra124_tsensor_groups), 210 194 .tfuse = &tegra124_soctherm_fuse, 211 195 .thresh_grain = TEGRA124_THRESH_GRAIN, 196 + .bptt = TEGRA124_BPTT, 197 + .use_ccroc = false, 212 198 };
+1
drivers/thermal/tegra/tegra132-soctherm.c
··· 193 193 .num_ttgs = ARRAY_SIZE(tegra132_tsensor_groups), 194 194 .tfuse = &tegra132_soctherm_fuse, 195 195 .thresh_grain = TEGRA132_THRESH_GRAIN, 196 + .use_ccroc = true, 196 197 };
+18
drivers/thermal/tegra/tegra210-soctherm.c
··· 29 29 #define TEGRA210_THERMTRIP_CPU_THRESH_MASK (0x1ff << 9) 30 30 #define TEGRA210_THERMTRIP_TSENSE_THRESH_MASK 0x1ff 31 31 32 + #define TEGRA210_THERMCTL_LVL0_UP_THRESH_MASK (0x1ff << 18) 33 + #define TEGRA210_THERMCTL_LVL0_DN_THRESH_MASK (0x1ff << 9) 34 + 32 35 #define TEGRA210_THRESH_GRAIN 500 36 + #define TEGRA210_BPTT 9 33 37 34 38 static const struct tegra_tsensor_configuration tegra210_tsensor_config = { 35 39 .tall = 16300, ··· 56 52 .thermtrip_any_en_mask = TEGRA210_THERMTRIP_ANY_EN_MASK, 57 53 .thermtrip_enable_mask = TEGRA210_THERMTRIP_CPU_EN_MASK, 58 54 .thermtrip_threshold_mask = TEGRA210_THERMTRIP_CPU_THRESH_MASK, 55 + .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_CPU, 56 + .thermctl_lvl0_up_thresh_mask = TEGRA210_THERMCTL_LVL0_UP_THRESH_MASK, 57 + .thermctl_lvl0_dn_thresh_mask = TEGRA210_THERMCTL_LVL0_DN_THRESH_MASK, 59 58 }; 60 59 61 60 static const struct tegra_tsensor_group tegra210_tsensor_group_gpu = { ··· 74 67 .thermtrip_any_en_mask = TEGRA210_THERMTRIP_ANY_EN_MASK, 75 68 .thermtrip_enable_mask = TEGRA210_THERMTRIP_GPU_EN_MASK, 76 69 .thermtrip_threshold_mask = TEGRA210_THERMTRIP_GPUMEM_THRESH_MASK, 70 + .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_GPU, 71 + .thermctl_lvl0_up_thresh_mask = TEGRA210_THERMCTL_LVL0_UP_THRESH_MASK, 72 + .thermctl_lvl0_dn_thresh_mask = TEGRA210_THERMCTL_LVL0_DN_THRESH_MASK, 77 73 }; 78 74 79 75 static const struct tegra_tsensor_group tegra210_tsensor_group_pll = { ··· 90 80 .thermtrip_any_en_mask = TEGRA210_THERMTRIP_ANY_EN_MASK, 91 81 .thermtrip_enable_mask = TEGRA210_THERMTRIP_TSENSE_EN_MASK, 92 82 .thermtrip_threshold_mask = TEGRA210_THERMTRIP_TSENSE_THRESH_MASK, 83 + .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_TSENSE, 84 + .thermctl_lvl0_up_thresh_mask = TEGRA210_THERMCTL_LVL0_UP_THRESH_MASK, 85 + .thermctl_lvl0_dn_thresh_mask = TEGRA210_THERMCTL_LVL0_DN_THRESH_MASK, 93 86 }; 94 87 95 88 static const struct tegra_tsensor_group tegra210_tsensor_group_mem = { ··· 108 95 .thermtrip_any_en_mask = TEGRA210_THERMTRIP_ANY_EN_MASK, 109 96 .thermtrip_enable_mask = TEGRA210_THERMTRIP_MEM_EN_MASK, 110 97 .thermtrip_threshold_mask = TEGRA210_THERMTRIP_GPUMEM_THRESH_MASK, 98 + .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_MEM, 99 + .thermctl_lvl0_up_thresh_mask = TEGRA210_THERMCTL_LVL0_UP_THRESH_MASK, 100 + .thermctl_lvl0_dn_thresh_mask = TEGRA210_THERMCTL_LVL0_DN_THRESH_MASK, 111 101 }; 112 102 113 103 static const struct tegra_tsensor_group *tegra210_tsensor_groups[] = { ··· 210 194 .num_ttgs = ARRAY_SIZE(tegra210_tsensor_groups), 211 195 .tfuse = &tegra210_soctherm_fuse, 212 196 .thresh_grain = TEGRA210_THRESH_GRAIN, 197 + .bptt = TEGRA210_BPTT, 198 + .use_ccroc = false, 213 199 };