diff options
| -rw-r--r-- | drivers/gpu/drm/nouveau/Makefile | 1 | ||||
| -rw-r--r-- | drivers/gpu/drm/nouveau/core/include/subdev/bios/therm.h | 46 | ||||
| -rw-r--r-- | drivers/gpu/drm/nouveau/core/subdev/bios/therm.c | 177 | ||||
| -rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_pm.c | 5 | ||||
| -rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_pm.h | 1 | ||||
| -rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_temp.c | 257 |
6 files changed, 282 insertions, 205 deletions
diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile index 1c506c5a9a48..b6a6fa7fbcd4 100644 --- a/drivers/gpu/drm/nouveau/Makefile +++ b/drivers/gpu/drm/nouveau/Makefile | |||
| @@ -35,6 +35,7 @@ nouveau-y += core/subdev/bios/i2c.o | |||
| 35 | nouveau-y += core/subdev/bios/init.o | 35 | nouveau-y += core/subdev/bios/init.o |
| 36 | nouveau-y += core/subdev/bios/mxm.o | 36 | nouveau-y += core/subdev/bios/mxm.o |
| 37 | nouveau-y += core/subdev/bios/pll.o | 37 | nouveau-y += core/subdev/bios/pll.o |
| 38 | nouveau-y += core/subdev/bios/therm.o | ||
| 38 | nouveau-y += core/subdev/clock/nv04.o | 39 | nouveau-y += core/subdev/clock/nv04.o |
| 39 | nouveau-y += core/subdev/clock/nv40.o | 40 | nouveau-y += core/subdev/clock/nv40.o |
| 40 | nouveau-y += core/subdev/clock/nv50.o | 41 | nouveau-y += core/subdev/clock/nv50.o |
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/therm.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/therm.h new file mode 100644 index 000000000000..a2c4296fc5f6 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/therm.h | |||
| @@ -0,0 +1,46 @@ | |||
| 1 | #ifndef __NVBIOS_THERM_H__ | ||
| 2 | #define __NVBIOS_THERM_H__ | ||
| 3 | |||
| 4 | struct nouveau_bios; | ||
| 5 | |||
| 6 | struct nvbios_therm_threshold { | ||
| 7 | u8 temp; | ||
| 8 | u8 hysteresis; | ||
| 9 | }; | ||
| 10 | |||
| 11 | struct nvbios_therm_sensor { | ||
| 12 | /* diode */ | ||
| 13 | s16 slope_mult; | ||
| 14 | s16 slope_div; | ||
| 15 | s16 offset_num; | ||
| 16 | s16 offset_den; | ||
| 17 | s8 offset_constant; | ||
| 18 | |||
| 19 | /* thresholds */ | ||
| 20 | struct nvbios_therm_threshold thrs_fan_boost; | ||
| 21 | struct nvbios_therm_threshold thrs_down_clock; | ||
| 22 | struct nvbios_therm_threshold thrs_critical; | ||
| 23 | struct nvbios_therm_threshold thrs_shutdown; | ||
| 24 | }; | ||
| 25 | |||
| 26 | struct nvbios_therm_fan { | ||
| 27 | u16 pwm_freq; | ||
| 28 | |||
| 29 | u8 min_duty; | ||
| 30 | u8 max_duty; | ||
| 31 | }; | ||
| 32 | |||
| 33 | enum nvbios_therm_domain { | ||
| 34 | NVBIOS_THERM_DOMAIN_CORE, | ||
| 35 | NVBIOS_THERM_DOMAIN_AMBIENT, | ||
| 36 | }; | ||
| 37 | |||
| 38 | int | ||
| 39 | nvbios_therm_sensor_parse(struct nouveau_bios *, enum nvbios_therm_domain, | ||
| 40 | struct nvbios_therm_sensor *); | ||
| 41 | |||
| 42 | int | ||
| 43 | nvbios_therm_fan_parse(struct nouveau_bios *, struct nvbios_therm_fan *); | ||
| 44 | |||
| 45 | |||
| 46 | #endif | ||
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/therm.c b/drivers/gpu/drm/nouveau/core/subdev/bios/therm.c new file mode 100644 index 000000000000..862a08a2ae27 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/therm.c | |||
| @@ -0,0 +1,177 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2012 Nouveau Community | ||
| 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: Martin Peres | ||
| 23 | */ | ||
| 24 | |||
| 25 | #include <subdev/bios.h> | ||
| 26 | #include <subdev/bios/bit.h> | ||
| 27 | #include <subdev/bios/therm.h> | ||
| 28 | |||
| 29 | static u16 | ||
| 30 | therm_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *len, u8 *cnt) | ||
| 31 | { | ||
| 32 | struct bit_entry bit_P; | ||
| 33 | u16 therm = 0; | ||
| 34 | |||
| 35 | if (!bit_entry(bios, 'P', &bit_P)) { | ||
| 36 | if (bit_P.version == 1) | ||
| 37 | therm = nv_ro16(bios, bit_P.offset + 12); | ||
| 38 | else if (bit_P.version == 2) | ||
| 39 | therm = nv_ro16(bios, bit_P.offset + 16); | ||
| 40 | else | ||
| 41 | nv_error(bios, | ||
| 42 | "unknown offset for thermal in BIT P %d\n", | ||
| 43 | bit_P.version); | ||
| 44 | } | ||
| 45 | |||
| 46 | /* exit now if we haven't found the thermal table */ | ||
| 47 | if (!therm) | ||
| 48 | return 0x0000; | ||
| 49 | |||
| 50 | *ver = nv_ro08(bios, therm + 0); | ||
| 51 | *hdr = nv_ro08(bios, therm + 1); | ||
| 52 | *len = nv_ro08(bios, therm + 2); | ||
| 53 | *cnt = nv_ro08(bios, therm + 3); | ||
| 54 | |||
| 55 | return therm + nv_ro08(bios, therm + 1); | ||
| 56 | } | ||
| 57 | |||
| 58 | u16 | ||
| 59 | nvbios_therm_entry(struct nouveau_bios *bios, int idx, u8 *ver, u8 *len) | ||
| 60 | { | ||
| 61 | u8 hdr, cnt; | ||
| 62 | u16 therm = therm_table(bios, ver, &hdr, len, &cnt); | ||
| 63 | if (therm && idx < cnt) | ||
| 64 | return therm + idx * *len; | ||
| 65 | return 0x0000; | ||
| 66 | } | ||
| 67 | |||
| 68 | int | ||
| 69 | nvbios_therm_sensor_parse(struct nouveau_bios *bios, | ||
| 70 | enum nvbios_therm_domain domain, | ||
| 71 | struct nvbios_therm_sensor *sensor) | ||
| 72 | { | ||
| 73 | s8 thrs_section, sensor_section, offset; | ||
| 74 | u8 ver, len, i; | ||
| 75 | u16 entry; | ||
| 76 | |||
| 77 | /* we only support the core domain for now */ | ||
| 78 | if (domain != NVBIOS_THERM_DOMAIN_CORE) | ||
| 79 | return -EINVAL; | ||
| 80 | |||
| 81 | /* Read the entries from the table */ | ||
| 82 | thrs_section = 0; | ||
| 83 | sensor_section = -1; | ||
| 84 | i = 0; | ||
| 85 | while ((entry = nvbios_therm_entry(bios, i++, &ver, &len))) { | ||
| 86 | s16 value = nv_ro16(bios, entry + 1); | ||
| 87 | |||
| 88 | switch (nv_ro08(bios, entry + 0)) { | ||
| 89 | case 0x0: | ||
| 90 | thrs_section = value; | ||
| 91 | if (value > 0) | ||
| 92 | return 0; /* we do not try to support ambient */ | ||
| 93 | break; | ||
| 94 | case 0x01: | ||
| 95 | sensor_section++; | ||
| 96 | if (sensor_section == 0) { | ||
| 97 | offset = ((s8) nv_ro08(bios, entry + 2)) / 2; | ||
| 98 | sensor->offset_constant = offset; | ||
| 99 | } | ||
| 100 | break; | ||
| 101 | |||
| 102 | case 0x04: | ||
| 103 | if (thrs_section == 0) { | ||
| 104 | sensor->thrs_critical.temp = (value & 0xff0) >> 4; | ||
| 105 | sensor->thrs_critical.hysteresis = value & 0xf; | ||
| 106 | } | ||
| 107 | break; | ||
| 108 | |||
| 109 | case 0x07: | ||
| 110 | if (thrs_section == 0) { | ||
| 111 | sensor->thrs_down_clock.temp = (value & 0xff0) >> 4; | ||
| 112 | sensor->thrs_down_clock.hysteresis = value & 0xf; | ||
| 113 | } | ||
| 114 | break; | ||
| 115 | |||
| 116 | case 0x08: | ||
| 117 | if (thrs_section == 0) { | ||
| 118 | sensor->thrs_fan_boost.temp = (value & 0xff0) >> 4; | ||
| 119 | sensor->thrs_fan_boost.hysteresis = value & 0xf; | ||
| 120 | } | ||
| 121 | break; | ||
| 122 | |||
| 123 | case 0x10: | ||
| 124 | if (sensor_section == 0) | ||
| 125 | sensor->offset_num = value; | ||
| 126 | break; | ||
| 127 | |||
| 128 | case 0x11: | ||
| 129 | if (sensor_section == 0) | ||
| 130 | sensor->offset_den = value; | ||
| 131 | break; | ||
| 132 | |||
| 133 | case 0x12: | ||
| 134 | if (sensor_section == 0) | ||
| 135 | sensor->slope_mult = value; | ||
| 136 | break; | ||
| 137 | |||
| 138 | case 0x13: | ||
| 139 | if (sensor_section == 0) | ||
| 140 | sensor->slope_div = value; | ||
| 141 | break; | ||
| 142 | case 0x32: | ||
| 143 | if (thrs_section == 0) { | ||
| 144 | sensor->thrs_shutdown.temp = (value & 0xff0) >> 4; | ||
| 145 | sensor->thrs_shutdown.hysteresis = value & 0xf; | ||
| 146 | } | ||
| 147 | break; | ||
| 148 | } | ||
| 149 | } | ||
| 150 | |||
| 151 | return 0; | ||
| 152 | } | ||
| 153 | |||
| 154 | int | ||
| 155 | nvbios_therm_fan_parse(struct nouveau_bios *bios, | ||
| 156 | struct nvbios_therm_fan *fan) | ||
| 157 | { | ||
| 158 | u8 ver, len, i; | ||
| 159 | u16 entry; | ||
| 160 | |||
| 161 | i = 0; | ||
| 162 | while ((entry = nvbios_therm_entry(bios, i++, &ver, &len))) { | ||
| 163 | s16 value = nv_ro16(bios, entry + 1); | ||
| 164 | |||
| 165 | switch (nv_ro08(bios, entry + 0)) { | ||
| 166 | case 0x22: | ||
| 167 | fan->min_duty = value & 0xff; | ||
| 168 | fan->max_duty = (value & 0xff00) >> 8; | ||
| 169 | break; | ||
| 170 | case 0x26: | ||
| 171 | fan->pwm_freq = value; | ||
| 172 | break; | ||
| 173 | } | ||
| 174 | } | ||
| 175 | |||
| 176 | return 0; | ||
| 177 | } | ||
diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c index d2f2de67f688..bdd50953488c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_pm.c +++ b/drivers/gpu/drm/nouveau/nouveau_pm.c | |||
| @@ -891,10 +891,7 @@ nouveau_pm_init(struct drm_device *dev) | |||
| 891 | } | 891 | } |
| 892 | pm->voltage_get = nouveau_voltage_gpio_get; | 892 | pm->voltage_get = nouveau_voltage_gpio_get; |
| 893 | pm->voltage_set = nouveau_voltage_gpio_set; | 893 | pm->voltage_set = nouveau_voltage_gpio_set; |
| 894 | if (device->chipset == 0x50) | 894 | pm->temp_get = nv84_temp_get; |
| 895 | pm->temp_get = nv40_temp_get; | ||
| 896 | else | ||
| 897 | pm->temp_get = nv84_temp_get; | ||
| 898 | pm->pwm_get = nv50_pm_pwm_get; | 895 | pm->pwm_get = nv50_pm_pwm_get; |
| 899 | pm->pwm_set = nv50_pm_pwm_set; | 896 | pm->pwm_set = nv50_pm_pwm_set; |
| 900 | } else | 897 | } else |
diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.h b/drivers/gpu/drm/nouveau/nouveau_pm.h index e2ec9c0ed567..2e39ccbd5d46 100644 --- a/drivers/gpu/drm/nouveau/nouveau_pm.h +++ b/drivers/gpu/drm/nouveau/nouveau_pm.h | |||
| @@ -148,7 +148,6 @@ struct nouveau_pm_temp_sensor_constants { | |||
| 148 | struct nouveau_pm_threshold_temp { | 148 | struct nouveau_pm_threshold_temp { |
| 149 | s16 critical; | 149 | s16 critical; |
| 150 | s16 down_clock; | 150 | s16 down_clock; |
| 151 | s16 fan_boost; | ||
| 152 | }; | 151 | }; |
| 153 | 152 | ||
| 154 | struct nouveau_pm_fan { | 153 | struct nouveau_pm_fan { |
diff --git a/drivers/gpu/drm/nouveau/nouveau_temp.c b/drivers/gpu/drm/nouveau/nouveau_temp.c index 7ae25e47be9f..5465abf87f18 100644 --- a/drivers/gpu/drm/nouveau/nouveau_temp.c +++ b/drivers/gpu/drm/nouveau/nouveau_temp.c | |||
| @@ -30,187 +30,23 @@ | |||
| 30 | #include "nouveau_pm.h" | 30 | #include "nouveau_pm.h" |
| 31 | 31 | ||
| 32 | #include <subdev/i2c.h> | 32 | #include <subdev/i2c.h> |
| 33 | 33 | #include <subdev/bios/therm.h> | |
| 34 | static void | ||
| 35 | nouveau_temp_vbios_parse(struct drm_device *dev, u8 *temp) | ||
| 36 | { | ||
| 37 | struct nouveau_drm *drm = nouveau_drm(dev); | ||
| 38 | struct nouveau_pm *pm = nouveau_pm(dev); | ||
| 39 | struct nouveau_pm_temp_sensor_constants *sensor = &pm->sensor_constants; | ||
| 40 | struct nouveau_pm_threshold_temp *temps = &pm->threshold_temp; | ||
| 41 | int i, headerlen, recordlen, entries; | ||
| 42 | |||
| 43 | if (!temp) { | ||
| 44 | NV_DEBUG(drm, "temperature table pointer invalid\n"); | ||
| 45 | return; | ||
| 46 | } | ||
| 47 | |||
| 48 | /* Set the default sensor's contants */ | ||
| 49 | sensor->offset_constant = 0; | ||
| 50 | sensor->offset_mult = 0; | ||
| 51 | sensor->offset_div = 1; | ||
| 52 | sensor->slope_mult = 1; | ||
| 53 | sensor->slope_div = 1; | ||
| 54 | |||
| 55 | /* Set the default temperature thresholds */ | ||
| 56 | temps->critical = 110; | ||
| 57 | temps->down_clock = 100; | ||
| 58 | temps->fan_boost = 90; | ||
| 59 | |||
| 60 | /* Set the default range for the pwm fan */ | ||
| 61 | pm->fan.min_duty = 30; | ||
| 62 | pm->fan.max_duty = 100; | ||
| 63 | |||
| 64 | /* Set the known default values to setup the temperature sensor */ | ||
| 65 | if (nv_device(drm->device)->card_type >= NV_40) { | ||
| 66 | switch (nv_device(drm->device)->chipset) { | ||
| 67 | case 0x43: | ||
| 68 | sensor->offset_mult = 32060; | ||
| 69 | sensor->offset_div = 1000; | ||
| 70 | sensor->slope_mult = 792; | ||
| 71 | sensor->slope_div = 1000; | ||
| 72 | break; | ||
| 73 | |||
| 74 | case 0x44: | ||
| 75 | case 0x47: | ||
| 76 | case 0x4a: | ||
| 77 | sensor->offset_mult = 27839; | ||
| 78 | sensor->offset_div = 1000; | ||
| 79 | sensor->slope_mult = 780; | ||
| 80 | sensor->slope_div = 1000; | ||
| 81 | break; | ||
| 82 | |||
| 83 | case 0x46: | ||
| 84 | sensor->offset_mult = -24775; | ||
| 85 | sensor->offset_div = 100; | ||
| 86 | sensor->slope_mult = 467; | ||
| 87 | sensor->slope_div = 10000; | ||
| 88 | break; | ||
| 89 | |||
| 90 | case 0x49: | ||
| 91 | sensor->offset_mult = -25051; | ||
| 92 | sensor->offset_div = 100; | ||
| 93 | sensor->slope_mult = 458; | ||
| 94 | sensor->slope_div = 10000; | ||
| 95 | break; | ||
| 96 | |||
| 97 | case 0x4b: | ||
| 98 | sensor->offset_mult = -24088; | ||
| 99 | sensor->offset_div = 100; | ||
| 100 | sensor->slope_mult = 442; | ||
| 101 | sensor->slope_div = 10000; | ||
| 102 | break; | ||
| 103 | |||
| 104 | case 0x50: | ||
| 105 | sensor->offset_mult = -22749; | ||
| 106 | sensor->offset_div = 100; | ||
| 107 | sensor->slope_mult = 431; | ||
| 108 | sensor->slope_div = 10000; | ||
| 109 | break; | ||
| 110 | |||
| 111 | case 0x67: | ||
| 112 | sensor->offset_mult = -26149; | ||
| 113 | sensor->offset_div = 100; | ||
| 114 | sensor->slope_mult = 484; | ||
| 115 | sensor->slope_div = 10000; | ||
| 116 | break; | ||
| 117 | } | ||
| 118 | } | ||
| 119 | |||
| 120 | headerlen = temp[1]; | ||
| 121 | recordlen = temp[2]; | ||
| 122 | entries = temp[3]; | ||
| 123 | temp = temp + headerlen; | ||
| 124 | |||
| 125 | /* Read the entries from the table */ | ||
| 126 | for (i = 0; i < entries; i++) { | ||
| 127 | s16 value = ROM16(temp[1]); | ||
| 128 | |||
| 129 | switch (temp[0]) { | ||
| 130 | case 0x01: | ||
| 131 | if ((value & 0x8f) == 0) | ||
| 132 | sensor->offset_constant = (value >> 9) & 0x7f; | ||
| 133 | break; | ||
| 134 | |||
| 135 | case 0x04: | ||
| 136 | if ((value & 0xf00f) == 0xa000) /* core */ | ||
| 137 | temps->critical = (value&0x0ff0) >> 4; | ||
| 138 | break; | ||
| 139 | |||
| 140 | case 0x07: | ||
| 141 | if ((value & 0xf00f) == 0xa000) /* core */ | ||
| 142 | temps->down_clock = (value&0x0ff0) >> 4; | ||
| 143 | break; | ||
| 144 | |||
| 145 | case 0x08: | ||
| 146 | if ((value & 0xf00f) == 0xa000) /* core */ | ||
| 147 | temps->fan_boost = (value&0x0ff0) >> 4; | ||
| 148 | break; | ||
| 149 | |||
| 150 | case 0x10: | ||
| 151 | sensor->offset_mult = value; | ||
| 152 | break; | ||
| 153 | |||
| 154 | case 0x11: | ||
| 155 | sensor->offset_div = value; | ||
| 156 | break; | ||
| 157 | |||
| 158 | case 0x12: | ||
| 159 | sensor->slope_mult = value; | ||
| 160 | break; | ||
| 161 | |||
| 162 | case 0x13: | ||
| 163 | sensor->slope_div = value; | ||
| 164 | break; | ||
| 165 | case 0x22: | ||
| 166 | pm->fan.min_duty = value & 0xff; | ||
| 167 | pm->fan.max_duty = (value & 0xff00) >> 8; | ||
| 168 | break; | ||
| 169 | case 0x26: | ||
| 170 | pm->fan.pwm_freq = value; | ||
| 171 | break; | ||
| 172 | } | ||
| 173 | temp += recordlen; | ||
| 174 | } | ||
| 175 | |||
| 176 | nouveau_temp_safety_checks(dev); | ||
| 177 | |||
| 178 | /* check the fan min/max settings */ | ||
| 179 | if (pm->fan.min_duty < 10) | ||
| 180 | pm->fan.min_duty = 10; | ||
| 181 | if (pm->fan.max_duty > 100) | ||
| 182 | pm->fan.max_duty = 100; | ||
| 183 | if (pm->fan.max_duty < pm->fan.min_duty) | ||
| 184 | pm->fan.max_duty = pm->fan.min_duty; | ||
| 185 | } | ||
| 186 | 34 | ||
| 187 | static int | 35 | static int |
| 188 | nv40_sensor_setup(struct drm_device *dev) | 36 | nv40_sensor_setup(struct drm_device *dev) |
| 189 | { | 37 | { |
| 190 | struct nouveau_device *device = nouveau_dev(dev); | 38 | struct nouveau_device *device = nouveau_dev(dev); |
| 191 | struct nouveau_drm *drm = nouveau_drm(dev); | 39 | struct nouveau_drm *drm = nouveau_drm(dev); |
| 192 | struct nouveau_pm *pm = nouveau_pm(dev); | ||
| 193 | struct nouveau_pm_temp_sensor_constants *sensor = &pm->sensor_constants; | ||
| 194 | s32 offset = sensor->offset_mult / sensor->offset_div; | ||
| 195 | s32 sensor_calibration; | ||
| 196 | |||
| 197 | /* set up the sensors */ | ||
| 198 | sensor_calibration = 120 - offset - sensor->offset_constant; | ||
| 199 | sensor_calibration = sensor_calibration * sensor->slope_div / | ||
| 200 | sensor->slope_mult; | ||
| 201 | 40 | ||
| 202 | if (nv_device(drm->device)->chipset >= 0x46) | 41 | /* enable ADC readout and disable the ALARM threshold */ |
| 203 | sensor_calibration |= 0x80000000; | 42 | if (nv_device(drm->device)->chipset >= 0x46) { |
| 204 | else | 43 | nv_mask(device, 0x15b8, 0x80000000, 0); |
| 205 | sensor_calibration |= 0x10000000; | 44 | nv_wr32(device, 0x15b0, 0x80003fff); |
| 206 | 45 | return nv_rd32(device, 0x15b4) & 0x3fff; | |
| 207 | nv_wr32(device, 0x0015b0, sensor_calibration); | 46 | } else { |
| 208 | 47 | nv_wr32(device, 0x15b0, 0xff); | |
| 209 | /* Wait for the sensor to update */ | 48 | return nv_rd32(device, 0x15b4) & 0xff; |
| 210 | msleep(5); | 49 | } |
| 211 | |||
| 212 | /* read */ | ||
| 213 | return nv_rd32(device, 0x0015b4) & 0x1fff; | ||
| 214 | } | 50 | } |
| 215 | 51 | ||
| 216 | int | 52 | int |
| @@ -220,20 +56,30 @@ nv40_temp_get(struct drm_device *dev) | |||
| 220 | struct nouveau_drm *drm = nouveau_drm(dev); | 56 | struct nouveau_drm *drm = nouveau_drm(dev); |
| 221 | struct nouveau_pm *pm = nouveau_pm(dev); | 57 | struct nouveau_pm *pm = nouveau_pm(dev); |
| 222 | struct nouveau_pm_temp_sensor_constants *sensor = &pm->sensor_constants; | 58 | struct nouveau_pm_temp_sensor_constants *sensor = &pm->sensor_constants; |
| 223 | int offset = sensor->offset_mult / sensor->offset_div; | ||
| 224 | int core_temp; | 59 | int core_temp; |
| 225 | 60 | ||
| 226 | if (nv_device(drm->device)->card_type >= NV_50) { | 61 | if (nv_device(drm->device)->chipset >= 0x46) { |
| 227 | core_temp = nv_rd32(device, 0x20008); | 62 | nv_wr32(device, 0x15b0, 0x80003fff); |
| 63 | core_temp = nv_rd32(device, 0x15b4) & 0x3fff; | ||
| 228 | } else { | 64 | } else { |
| 229 | core_temp = nv_rd32(device, 0x0015b4) & 0x1fff; | 65 | nv_wr32(device, 0x15b0, 0xff); |
| 230 | /* Setup the sensor if the temperature is 0 */ | 66 | core_temp = nv_rd32(device, 0x15b4) & 0xff; |
| 231 | if (core_temp == 0) | ||
| 232 | core_temp = nv40_sensor_setup(dev); | ||
| 233 | } | 67 | } |
| 234 | 68 | ||
| 69 | /* Setup the sensor if the temperature is 0 */ | ||
| 70 | if (core_temp == 0) | ||
| 71 | core_temp = nv40_sensor_setup(dev); | ||
| 72 | |||
| 73 | if (sensor->slope_div == 0) | ||
| 74 | sensor->slope_div = 1; | ||
| 75 | if (sensor->offset_div == 0) | ||
| 76 | sensor->offset_div = 1; | ||
| 77 | if (sensor->slope_mult < 1) | ||
| 78 | sensor->slope_mult = 1; | ||
| 79 | |||
| 235 | core_temp = core_temp * sensor->slope_mult / sensor->slope_div; | 80 | core_temp = core_temp * sensor->slope_mult / sensor->slope_div; |
| 236 | core_temp = core_temp + offset + sensor->offset_constant; | 81 | core_temp = core_temp + sensor->offset_mult / sensor->offset_div; |
| 82 | core_temp = core_temp + sensor->offset_constant - 8; | ||
| 237 | 83 | ||
| 238 | return core_temp; | 84 | return core_temp; |
| 239 | } | 85 | } |
| @@ -260,11 +106,6 @@ nouveau_temp_safety_checks(struct drm_device *dev) | |||
| 260 | temps->down_clock = 110; | 106 | temps->down_clock = 110; |
| 261 | else if (temps->down_clock < 60) | 107 | else if (temps->down_clock < 60) |
| 262 | temps->down_clock = 60; | 108 | temps->down_clock = 60; |
| 263 | |||
| 264 | if (temps->fan_boost > 100) | ||
| 265 | temps->fan_boost = 100; | ||
| 266 | else if (temps->fan_boost < 40) | ||
| 267 | temps->fan_boost = 40; | ||
| 268 | } | 109 | } |
| 269 | 110 | ||
| 270 | static bool | 111 | static bool |
| @@ -309,24 +150,40 @@ void | |||
| 309 | nouveau_temp_init(struct drm_device *dev) | 150 | nouveau_temp_init(struct drm_device *dev) |
| 310 | { | 151 | { |
| 311 | struct nouveau_drm *drm = nouveau_drm(dev); | 152 | struct nouveau_drm *drm = nouveau_drm(dev); |
| 312 | struct nvbios *bios = &drm->vbios; | 153 | struct nouveau_device *device = nv_device(drm->device); |
| 313 | struct bit_entry P; | 154 | struct nouveau_bios *bios = nouveau_bios(device); |
| 314 | u8 *temp = NULL; | 155 | struct nouveau_pm *pm = nouveau_pm(dev); |
| 156 | struct nouveau_pm_temp_sensor_constants *sensor = &pm->sensor_constants; | ||
| 157 | struct nouveau_pm_threshold_temp *temps = &pm->threshold_temp; | ||
| 158 | struct nvbios_therm_sensor bios_sensor; | ||
| 159 | struct nvbios_therm_fan bios_fan; | ||
| 315 | 160 | ||
| 316 | if (bios->type == NVBIOS_BIT) { | 161 | /* store some safe defaults */ |
| 317 | if (bit_table(dev, 'P', &P)) | 162 | sensor->offset_constant = 0; |
| 318 | return; | 163 | sensor->offset_mult = 0; |
| 164 | sensor->offset_div = 1; | ||
| 165 | sensor->slope_mult = 1; | ||
| 166 | sensor->slope_div = 1; | ||
| 319 | 167 | ||
| 320 | if (P.version == 1) | 168 | if (!nvbios_therm_sensor_parse(bios, NVBIOS_THERM_DOMAIN_CORE, |
| 321 | temp = ROMPTR(dev, P.data[12]); | 169 | &bios_sensor)) { |
| 322 | else if (P.version == 2) | 170 | sensor->slope_mult = bios_sensor.slope_mult; |
| 323 | temp = ROMPTR(dev, P.data[16]); | 171 | sensor->slope_div = bios_sensor.slope_div; |
| 324 | else | 172 | sensor->offset_mult = bios_sensor.offset_num; |
| 325 | NV_WARN(drm, "unknown temp for BIT P %d\n", P.version); | 173 | sensor->offset_div = bios_sensor.offset_den; |
| 174 | sensor->offset_constant = bios_sensor.offset_constant; | ||
| 326 | 175 | ||
| 327 | nouveau_temp_vbios_parse(dev, temp); | 176 | temps->down_clock = bios_sensor.thrs_down_clock.temp; |
| 177 | temps->critical = bios_sensor.thrs_critical.temp; | ||
| 328 | } | 178 | } |
| 329 | 179 | ||
| 180 | if (nvbios_therm_fan_parse(bios, &bios_fan)) { | ||
| 181 | pm->fan.min_duty = bios_fan.min_duty; | ||
| 182 | pm->fan.max_duty = bios_fan.max_duty; | ||
| 183 | pm->fan.pwm_freq = bios_fan.pwm_freq; | ||
| 184 | } | ||
| 185 | |||
| 186 | nouveau_temp_safety_checks(dev); | ||
| 330 | nouveau_temp_probe_i2c(dev); | 187 | nouveau_temp_probe_i2c(dev); |
| 331 | } | 188 | } |
| 332 | 189 | ||
