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

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

DEFINITIONS

This source file includes following definitions.
  1. nv40_sensor_style
  2. nv40_sensor_setup
  3. nv40_temp_get
  4. nv40_fan_pwm_ctrl
  5. nv40_fan_pwm_get
  6. nv40_fan_pwm_set
  7. nv40_therm_intr
  8. nv40_therm_init
  9. nv40_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 enum nv40_sensor_style { INVALID_STYLE = -1, OLD_STYLE = 0, NEW_STYLE = 1 };
  28 
  29 static enum nv40_sensor_style
  30 nv40_sensor_style(struct nvkm_therm *therm)
  31 {
  32         switch (therm->subdev.device->chipset) {
  33         case 0x43:
  34         case 0x44:
  35         case 0x4a:
  36         case 0x47:
  37                 return OLD_STYLE;
  38         case 0x46:
  39         case 0x49:
  40         case 0x4b:
  41         case 0x4e:
  42         case 0x4c:
  43         case 0x67:
  44         case 0x68:
  45         case 0x63:
  46                 return NEW_STYLE;
  47         default:
  48                 return INVALID_STYLE;
  49         }
  50 }
  51 
  52 static int
  53 nv40_sensor_setup(struct nvkm_therm *therm)
  54 {
  55         struct nvkm_device *device = therm->subdev.device;
  56         enum nv40_sensor_style style = nv40_sensor_style(therm);
  57 
  58         /* enable ADC readout and disable the ALARM threshold */
  59         if (style == NEW_STYLE) {
  60                 nvkm_mask(device, 0x15b8, 0x80000000, 0);
  61                 nvkm_wr32(device, 0x15b0, 0x80003fff);
  62                 mdelay(20); /* wait for the temperature to stabilize */
  63                 return nvkm_rd32(device, 0x15b4) & 0x3fff;
  64         } else if (style == OLD_STYLE) {
  65                 nvkm_wr32(device, 0x15b0, 0xff);
  66                 mdelay(20); /* wait for the temperature to stabilize */
  67                 return nvkm_rd32(device, 0x15b4) & 0xff;
  68         } else
  69                 return -ENODEV;
  70 }
  71 
  72 static int
  73 nv40_temp_get(struct nvkm_therm *therm)
  74 {
  75         struct nvkm_device *device = therm->subdev.device;
  76         struct nvbios_therm_sensor *sensor = &therm->bios_sensor;
  77         enum nv40_sensor_style style = nv40_sensor_style(therm);
  78         int core_temp;
  79 
  80         if (style == NEW_STYLE) {
  81                 nvkm_wr32(device, 0x15b0, 0x80003fff);
  82                 core_temp = nvkm_rd32(device, 0x15b4) & 0x3fff;
  83         } else if (style == OLD_STYLE) {
  84                 nvkm_wr32(device, 0x15b0, 0xff);
  85                 core_temp = nvkm_rd32(device, 0x15b4) & 0xff;
  86         } else
  87                 return -ENODEV;
  88 
  89         /* if the slope or the offset is unset, do no use the sensor */
  90         if (!sensor->slope_div || !sensor->slope_mult ||
  91             !sensor->offset_num || !sensor->offset_den)
  92             return -ENODEV;
  93 
  94         core_temp = core_temp * sensor->slope_mult / sensor->slope_div;
  95         core_temp = core_temp + sensor->offset_num / sensor->offset_den;
  96         core_temp = core_temp + sensor->offset_constant - 8;
  97 
  98         /* reserve negative temperatures for errors */
  99         if (core_temp < 0)
 100                 core_temp = 0;
 101 
 102         return core_temp;
 103 }
 104 
 105 static int
 106 nv40_fan_pwm_ctrl(struct nvkm_therm *therm, int line, bool enable)
 107 {
 108         struct nvkm_subdev *subdev = &therm->subdev;
 109         struct nvkm_device *device = subdev->device;
 110         u32 mask = enable ? 0x80000000 : 0x00000000;
 111         if      (line == 2) nvkm_mask(device, 0x0010f0, 0x80000000, mask);
 112         else if (line == 9) nvkm_mask(device, 0x0015f4, 0x80000000, mask);
 113         else {
 114                 nvkm_error(subdev, "unknown pwm ctrl for gpio %d\n", line);
 115                 return -ENODEV;
 116         }
 117         return 0;
 118 }
 119 
 120 static int
 121 nv40_fan_pwm_get(struct nvkm_therm *therm, int line, u32 *divs, u32 *duty)
 122 {
 123         struct nvkm_subdev *subdev = &therm->subdev;
 124         struct nvkm_device *device = subdev->device;
 125         if (line == 2) {
 126                 u32 reg = nvkm_rd32(device, 0x0010f0);
 127                 if (reg & 0x80000000) {
 128                         *duty = (reg & 0x7fff0000) >> 16;
 129                         *divs = (reg & 0x00007fff);
 130                         return 0;
 131                 }
 132         } else
 133         if (line == 9) {
 134                 u32 reg = nvkm_rd32(device, 0x0015f4);
 135                 if (reg & 0x80000000) {
 136                         *divs = nvkm_rd32(device, 0x0015f8);
 137                         *duty = (reg & 0x7fffffff);
 138                         return 0;
 139                 }
 140         } else {
 141                 nvkm_error(subdev, "unknown pwm ctrl for gpio %d\n", line);
 142                 return -ENODEV;
 143         }
 144 
 145         return -EINVAL;
 146 }
 147 
 148 static int
 149 nv40_fan_pwm_set(struct nvkm_therm *therm, int line, u32 divs, u32 duty)
 150 {
 151         struct nvkm_subdev *subdev = &therm->subdev;
 152         struct nvkm_device *device = subdev->device;
 153         if (line == 2) {
 154                 nvkm_mask(device, 0x0010f0, 0x7fff7fff, (duty << 16) | divs);
 155         } else
 156         if (line == 9) {
 157                 nvkm_wr32(device, 0x0015f8, divs);
 158                 nvkm_mask(device, 0x0015f4, 0x7fffffff, duty);
 159         } else {
 160                 nvkm_error(subdev, "unknown pwm ctrl for gpio %d\n", line);
 161                 return -ENODEV;
 162         }
 163 
 164         return 0;
 165 }
 166 
 167 void
 168 nv40_therm_intr(struct nvkm_therm *therm)
 169 {
 170         struct nvkm_subdev *subdev = &therm->subdev;
 171         struct nvkm_device *device = subdev->device;
 172         uint32_t stat = nvkm_rd32(device, 0x1100);
 173 
 174         /* traitement */
 175 
 176         /* ack all IRQs */
 177         nvkm_wr32(device, 0x1100, 0x70000);
 178 
 179         nvkm_error(subdev, "THERM received an IRQ: stat = %x\n", stat);
 180 }
 181 
 182 static void
 183 nv40_therm_init(struct nvkm_therm *therm)
 184 {
 185         nv40_sensor_setup(therm);
 186 }
 187 
 188 static const struct nvkm_therm_func
 189 nv40_therm = {
 190         .init = nv40_therm_init,
 191         .intr = nv40_therm_intr,
 192         .pwm_ctrl = nv40_fan_pwm_ctrl,
 193         .pwm_get = nv40_fan_pwm_get,
 194         .pwm_set = nv40_fan_pwm_set,
 195         .temp_get = nv40_temp_get,
 196         .program_alarms = nvkm_therm_program_alarms_polling,
 197 };
 198 
 199 int
 200 nv40_therm_new(struct nvkm_device *device, int index,
 201                struct nvkm_therm **ptherm)
 202 {
 203         return nvkm_therm_new_(&nv40_therm, device, index, ptherm);
 204 }

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