Home | History | Annotate | Line # | Download | only in therm
      1 /*	$NetBSD: nouveau_nvkm_subdev_therm_g84.c,v 1.3 2021/12/18 23:45:41 riastradh Exp $	*/
      2 
      3 /*
      4  * Copyright 2012 Red Hat Inc.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the "Software"),
      8  * to deal in the Software without restriction, including without limitation
      9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     10  * and/or sell copies of the Software, and to permit persons to whom the
     11  * Software is furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included in
     14  * all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     19  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
     20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     22  * OTHER DEALINGS IN THE SOFTWARE.
     23  *
     24  * Authors: Ben Skeggs
     25  * 	    Martin Peres
     26  */
     27 #include <sys/cdefs.h>
     28 __KERNEL_RCSID(0, "$NetBSD: nouveau_nvkm_subdev_therm_g84.c,v 1.3 2021/12/18 23:45:41 riastradh Exp $");
     29 
     30 #include "priv.h"
     31 
     32 #include <subdev/fuse.h>
     33 
     34 int
     35 g84_temp_get(struct nvkm_therm *therm)
     36 {
     37 	struct nvkm_device *device = therm->subdev.device;
     38 
     39 	if (nvkm_fuse_read(device->fuse, 0x1a8) == 1)
     40 		return nvkm_rd32(device, 0x20400);
     41 	else
     42 		return -ENODEV;
     43 }
     44 
     45 void
     46 g84_sensor_setup(struct nvkm_therm *therm)
     47 {
     48 	struct nvkm_device *device = therm->subdev.device;
     49 
     50 	/* enable temperature reading for cards with insane defaults */
     51 	if (nvkm_fuse_read(device->fuse, 0x1a8) == 1) {
     52 		nvkm_mask(device, 0x20008, 0x80008000, 0x80000000);
     53 		nvkm_mask(device, 0x2000c, 0x80000003, 0x00000000);
     54 		mdelay(20); /* wait for the temperature to stabilize */
     55 	}
     56 }
     57 
     58 static void
     59 g84_therm_program_alarms(struct nvkm_therm *therm)
     60 {
     61 	struct nvbios_therm_sensor *sensor = &therm->bios_sensor;
     62 	struct nvkm_subdev *subdev = &therm->subdev;
     63 	struct nvkm_device *device = subdev->device;
     64 	unsigned long flags;
     65 
     66 	spin_lock_irqsave(&therm->sensor.alarm_program_lock, flags);
     67 
     68 	/* enable RISING and FALLING IRQs for shutdown, THRS 0, 1, 2 and 4 */
     69 	nvkm_wr32(device, 0x20000, 0x000003ff);
     70 
     71 	/* shutdown: The computer should be shutdown when reached */
     72 	nvkm_wr32(device, 0x20484, sensor->thrs_shutdown.hysteresis);
     73 	nvkm_wr32(device, 0x20480, sensor->thrs_shutdown.temp);
     74 
     75 	/* THRS_1 : fan boost*/
     76 	nvkm_wr32(device, 0x204c4, sensor->thrs_fan_boost.temp);
     77 
     78 	/* THRS_2 : critical */
     79 	nvkm_wr32(device, 0x204c0, sensor->thrs_critical.temp);
     80 
     81 	/* THRS_4 : down clock */
     82 	nvkm_wr32(device, 0x20414, sensor->thrs_down_clock.temp);
     83 	spin_unlock_irqrestore(&therm->sensor.alarm_program_lock, flags);
     84 
     85 	nvkm_debug(subdev,
     86 		   "Programmed thresholds [ %d(%d), %d(%d), %d(%d), %d(%d) ]\n",
     87 		   sensor->thrs_fan_boost.temp,
     88 		   sensor->thrs_fan_boost.hysteresis,
     89 		   sensor->thrs_down_clock.temp,
     90 		   sensor->thrs_down_clock.hysteresis,
     91 		   sensor->thrs_critical.temp,
     92 		   sensor->thrs_critical.hysteresis,
     93 		   sensor->thrs_shutdown.temp,
     94 		   sensor->thrs_shutdown.hysteresis);
     95 
     96 }
     97 
     98 /* must be called with alarm_program_lock taken ! */
     99 static void
    100 g84_therm_threshold_hyst_emulation(struct nvkm_therm *therm,
    101 				   uint32_t thrs_reg, u8 status_bit,
    102 				   const struct nvbios_therm_threshold *thrs,
    103 				   enum nvkm_therm_thrs thrs_name)
    104 {
    105 	struct nvkm_device *device = therm->subdev.device;
    106 	enum nvkm_therm_thrs_direction direction;
    107 	enum nvkm_therm_thrs_state prev_state, new_state;
    108 	int temp, cur;
    109 
    110 	prev_state = nvkm_therm_sensor_get_threshold_state(therm, thrs_name);
    111 	temp = nvkm_rd32(device, thrs_reg);
    112 
    113 	/* program the next threshold */
    114 	if (temp == thrs->temp) {
    115 		nvkm_wr32(device, thrs_reg, thrs->temp - thrs->hysteresis);
    116 		new_state = NVKM_THERM_THRS_HIGHER;
    117 	} else {
    118 		nvkm_wr32(device, thrs_reg, thrs->temp);
    119 		new_state = NVKM_THERM_THRS_LOWER;
    120 	}
    121 
    122 	/* fix the state (in case someone reprogrammed the alarms) */
    123 	cur = therm->func->temp_get(therm);
    124 	if (new_state == NVKM_THERM_THRS_LOWER && cur > thrs->temp)
    125 		new_state = NVKM_THERM_THRS_HIGHER;
    126 	else if (new_state == NVKM_THERM_THRS_HIGHER &&
    127 		cur < thrs->temp - thrs->hysteresis)
    128 		new_state = NVKM_THERM_THRS_LOWER;
    129 	nvkm_therm_sensor_set_threshold_state(therm, thrs_name, new_state);
    130 
    131 	/* find the direction */
    132 	if (prev_state < new_state)
    133 		direction = NVKM_THERM_THRS_RISING;
    134 	else if (prev_state > new_state)
    135 		direction = NVKM_THERM_THRS_FALLING;
    136 	else
    137 		return;
    138 
    139 	/* advertise a change in direction */
    140 	nvkm_therm_sensor_event(therm, thrs_name, direction);
    141 }
    142 
    143 static void
    144 g84_therm_intr(struct nvkm_therm *therm)
    145 {
    146 	struct nvkm_subdev *subdev = &therm->subdev;
    147 	struct nvkm_device *device = subdev->device;
    148 	struct nvbios_therm_sensor *sensor = &therm->bios_sensor;
    149 	unsigned long flags;
    150 	uint32_t intr;
    151 
    152 	spin_lock_irqsave(&therm->sensor.alarm_program_lock, flags);
    153 
    154 	intr = nvkm_rd32(device, 0x20100) & 0x3ff;
    155 
    156 	/* THRS_4: downclock */
    157 	if (intr & 0x002) {
    158 		g84_therm_threshold_hyst_emulation(therm, 0x20414, 24,
    159 						   &sensor->thrs_down_clock,
    160 						   NVKM_THERM_THRS_DOWNCLOCK);
    161 		intr &= ~0x002;
    162 	}
    163 
    164 	/* shutdown */
    165 	if (intr & 0x004) {
    166 		g84_therm_threshold_hyst_emulation(therm, 0x20480, 20,
    167 						   &sensor->thrs_shutdown,
    168 						   NVKM_THERM_THRS_SHUTDOWN);
    169 		intr &= ~0x004;
    170 	}
    171 
    172 	/* THRS_1 : fan boost */
    173 	if (intr & 0x008) {
    174 		g84_therm_threshold_hyst_emulation(therm, 0x204c4, 21,
    175 						   &sensor->thrs_fan_boost,
    176 						   NVKM_THERM_THRS_FANBOOST);
    177 		intr &= ~0x008;
    178 	}
    179 
    180 	/* THRS_2 : critical */
    181 	if (intr & 0x010) {
    182 		g84_therm_threshold_hyst_emulation(therm, 0x204c0, 22,
    183 						   &sensor->thrs_critical,
    184 						   NVKM_THERM_THRS_CRITICAL);
    185 		intr &= ~0x010;
    186 	}
    187 
    188 	if (intr)
    189 		nvkm_error(subdev, "intr %08x\n", intr);
    190 
    191 	/* ACK everything */
    192 	nvkm_wr32(device, 0x20100, 0xffffffff);
    193 	nvkm_wr32(device, 0x1100, 0x10000); /* PBUS */
    194 
    195 	spin_unlock_irqrestore(&therm->sensor.alarm_program_lock, flags);
    196 }
    197 
    198 void
    199 g84_therm_fini(struct nvkm_therm *therm)
    200 {
    201 	struct nvkm_device *device = therm->subdev.device;
    202 
    203 	/* Disable PTherm IRQs */
    204 	nvkm_wr32(device, 0x20000, 0x00000000);
    205 
    206 	/* ACK all PTherm IRQs */
    207 	nvkm_wr32(device, 0x20100, 0xffffffff);
    208 	nvkm_wr32(device, 0x1100, 0x10000); /* PBUS */
    209 }
    210 
    211 void
    212 g84_therm_init(struct nvkm_therm *therm)
    213 {
    214 	g84_sensor_setup(therm);
    215 }
    216 
    217 static const struct nvkm_therm_func
    218 g84_therm = {
    219 	.init = g84_therm_init,
    220 	.fini = g84_therm_fini,
    221 	.intr = g84_therm_intr,
    222 	.pwm_ctrl = nv50_fan_pwm_ctrl,
    223 	.pwm_get = nv50_fan_pwm_get,
    224 	.pwm_set = nv50_fan_pwm_set,
    225 	.pwm_clock = nv50_fan_pwm_clock,
    226 	.temp_get = g84_temp_get,
    227 	.program_alarms = g84_therm_program_alarms,
    228 };
    229 
    230 int
    231 g84_therm_new(struct nvkm_device *device, int index, struct nvkm_therm **ptherm)
    232 {
    233 	struct nvkm_therm *therm;
    234 	int ret;
    235 
    236 	ret = nvkm_therm_new_(&g84_therm, device, index, &therm);
    237 	*ptherm = therm;
    238 	if (ret)
    239 		return ret;
    240 
    241 	/* init the thresholds */
    242 	nvkm_therm_sensor_set_threshold_state(therm, NVKM_THERM_THRS_SHUTDOWN,
    243 						     NVKM_THERM_THRS_LOWER);
    244 	nvkm_therm_sensor_set_threshold_state(therm, NVKM_THERM_THRS_FANBOOST,
    245 						     NVKM_THERM_THRS_LOWER);
    246 	nvkm_therm_sensor_set_threshold_state(therm, NVKM_THERM_THRS_CRITICAL,
    247 						     NVKM_THERM_THRS_LOWER);
    248 	nvkm_therm_sensor_set_threshold_state(therm, NVKM_THERM_THRS_DOWNCLOCK,
    249 						     NVKM_THERM_THRS_LOWER);
    250 	return 0;
    251 }
    252