root/drivers/gpu/drm/nouveau/nvkm/subdev/therm/g84.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. g84_temp_get
  2. g84_sensor_setup
  3. g84_therm_program_alarms
  4. g84_therm_threshold_hyst_emulation
  5. g84_therm_intr
  6. g84_therm_fini
  7. g84_therm_init
  8. g84_therm_new

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

/* [<][>][^][v][top][bottom][index][help] */