Path: blob/master/drivers/gpu/drm/nouveau/nouveau_temp.c
15112 views
/*1* Copyright 2010 PathScale inc.2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice shall be included in11* all copies or substantial portions of the Software.12*13* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR14* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,15* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL16* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR17* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,18* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR19* OTHER DEALINGS IN THE SOFTWARE.20*21* Authors: Martin Peres22*/2324#include "drmP.h"2526#include "nouveau_drv.h"27#include "nouveau_pm.h"2829static void30nouveau_temp_vbios_parse(struct drm_device *dev, u8 *temp)31{32struct drm_nouveau_private *dev_priv = dev->dev_private;33struct nouveau_pm_engine *pm = &dev_priv->engine.pm;34struct nouveau_pm_temp_sensor_constants *sensor = &pm->sensor_constants;35struct nouveau_pm_threshold_temp *temps = &pm->threshold_temp;36int i, headerlen, recordlen, entries;3738if (!temp) {39NV_DEBUG(dev, "temperature table pointer invalid\n");40return;41}4243/* Set the default sensor's contants */44sensor->offset_constant = 0;45sensor->offset_mult = 1;46sensor->offset_div = 1;47sensor->slope_mult = 1;48sensor->slope_div = 1;4950/* Set the default temperature thresholds */51temps->critical = 110;52temps->down_clock = 100;53temps->fan_boost = 90;5455/* Set the known default values to setup the temperature sensor */56if (dev_priv->card_type >= NV_40) {57switch (dev_priv->chipset) {58case 0x43:59sensor->offset_mult = 32060;60sensor->offset_div = 1000;61sensor->slope_mult = 792;62sensor->slope_div = 1000;63break;6465case 0x44:66case 0x47:67case 0x4a:68sensor->offset_mult = 27839;69sensor->offset_div = 1000;70sensor->slope_mult = 780;71sensor->slope_div = 1000;72break;7374case 0x46:75sensor->offset_mult = -24775;76sensor->offset_div = 100;77sensor->slope_mult = 467;78sensor->slope_div = 10000;79break;8081case 0x49:82sensor->offset_mult = -25051;83sensor->offset_div = 100;84sensor->slope_mult = 458;85sensor->slope_div = 10000;86break;8788case 0x4b:89sensor->offset_mult = -24088;90sensor->offset_div = 100;91sensor->slope_mult = 442;92sensor->slope_div = 10000;93break;9495case 0x50:96sensor->offset_mult = -22749;97sensor->offset_div = 100;98sensor->slope_mult = 431;99sensor->slope_div = 10000;100break;101}102}103104headerlen = temp[1];105recordlen = temp[2];106entries = temp[3];107temp = temp + headerlen;108109/* Read the entries from the table */110for (i = 0; i < entries; i++) {111u16 value = ROM16(temp[1]);112113switch (temp[0]) {114case 0x01:115if ((value & 0x8f) == 0)116sensor->offset_constant = (value >> 9) & 0x7f;117break;118119case 0x04:120if ((value & 0xf00f) == 0xa000) /* core */121temps->critical = (value&0x0ff0) >> 4;122break;123124case 0x07:125if ((value & 0xf00f) == 0xa000) /* core */126temps->down_clock = (value&0x0ff0) >> 4;127break;128129case 0x08:130if ((value & 0xf00f) == 0xa000) /* core */131temps->fan_boost = (value&0x0ff0) >> 4;132break;133134case 0x10:135sensor->offset_mult = value;136break;137138case 0x11:139sensor->offset_div = value;140break;141142case 0x12:143sensor->slope_mult = value;144break;145146case 0x13:147sensor->slope_div = value;148break;149}150temp += recordlen;151}152153nouveau_temp_safety_checks(dev);154}155156static int157nv40_sensor_setup(struct drm_device *dev)158{159struct drm_nouveau_private *dev_priv = dev->dev_private;160struct nouveau_pm_engine *pm = &dev_priv->engine.pm;161struct nouveau_pm_temp_sensor_constants *sensor = &pm->sensor_constants;162u32 offset = sensor->offset_mult / sensor->offset_div;163u32 sensor_calibration;164165/* set up the sensors */166sensor_calibration = 120 - offset - sensor->offset_constant;167sensor_calibration = sensor_calibration * sensor->slope_div /168sensor->slope_mult;169170if (dev_priv->chipset >= 0x46)171sensor_calibration |= 0x80000000;172else173sensor_calibration |= 0x10000000;174175nv_wr32(dev, 0x0015b0, sensor_calibration);176177/* Wait for the sensor to update */178msleep(5);179180/* read */181return nv_rd32(dev, 0x0015b4) & 0x1fff;182}183184int185nv40_temp_get(struct drm_device *dev)186{187struct drm_nouveau_private *dev_priv = dev->dev_private;188struct nouveau_pm_engine *pm = &dev_priv->engine.pm;189struct nouveau_pm_temp_sensor_constants *sensor = &pm->sensor_constants;190int offset = sensor->offset_mult / sensor->offset_div;191int core_temp;192193if (dev_priv->card_type >= NV_50) {194core_temp = nv_rd32(dev, 0x20008);195} else {196core_temp = nv_rd32(dev, 0x0015b4) & 0x1fff;197/* Setup the sensor if the temperature is 0 */198if (core_temp == 0)199core_temp = nv40_sensor_setup(dev);200}201202core_temp = core_temp * sensor->slope_mult / sensor->slope_div;203core_temp = core_temp + offset + sensor->offset_constant;204205return core_temp;206}207208int209nv84_temp_get(struct drm_device *dev)210{211return nv_rd32(dev, 0x20400);212}213214void215nouveau_temp_safety_checks(struct drm_device *dev)216{217struct drm_nouveau_private *dev_priv = dev->dev_private;218struct nouveau_pm_engine *pm = &dev_priv->engine.pm;219struct nouveau_pm_threshold_temp *temps = &pm->threshold_temp;220221if (temps->critical > 120)222temps->critical = 120;223else if (temps->critical < 80)224temps->critical = 80;225226if (temps->down_clock > 110)227temps->down_clock = 110;228else if (temps->down_clock < 60)229temps->down_clock = 60;230231if (temps->fan_boost > 100)232temps->fan_boost = 100;233else if (temps->fan_boost < 40)234temps->fan_boost = 40;235}236237static bool238probe_monitoring_device(struct nouveau_i2c_chan *i2c,239struct i2c_board_info *info)240{241struct i2c_client *client;242243request_module("%s%s", I2C_MODULE_PREFIX, info->type);244245client = i2c_new_device(&i2c->adapter, info);246if (!client)247return false;248249if (!client->driver || client->driver->detect(client, info)) {250i2c_unregister_device(client);251return false;252}253254return true;255}256257static void258nouveau_temp_probe_i2c(struct drm_device *dev)259{260struct drm_nouveau_private *dev_priv = dev->dev_private;261struct dcb_table *dcb = &dev_priv->vbios.dcb;262struct i2c_board_info info[] = {263{ I2C_BOARD_INFO("w83l785ts", 0x2d) },264{ I2C_BOARD_INFO("w83781d", 0x2d) },265{ I2C_BOARD_INFO("adt7473", 0x2e) },266{ I2C_BOARD_INFO("f75375", 0x2e) },267{ I2C_BOARD_INFO("lm99", 0x4c) },268{ }269};270int idx = (dcb->version >= 0x40 ?271dcb->i2c_default_indices & 0xf : 2);272273nouveau_i2c_identify(dev, "monitoring device", info,274probe_monitoring_device, idx);275}276277void278nouveau_temp_init(struct drm_device *dev)279{280struct drm_nouveau_private *dev_priv = dev->dev_private;281struct nvbios *bios = &dev_priv->vbios;282struct bit_entry P;283u8 *temp = NULL;284285if (bios->type == NVBIOS_BIT) {286if (bit_table(dev, 'P', &P))287return;288289if (P.version == 1)290temp = ROMPTR(bios, P.data[12]);291else if (P.version == 2)292temp = ROMPTR(bios, P.data[16]);293else294NV_WARN(dev, "unknown temp for BIT P %d\n", P.version);295296nouveau_temp_vbios_parse(dev, temp);297}298299nouveau_temp_probe_i2c(dev);300}301302void303nouveau_temp_fini(struct drm_device *dev)304{305306}307308309