Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
  1/*
  2 * Copyright 2010 PathScale 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: Martin Peres
 23 */
 24
 25#include "drmP.h"
 26
 27#include "nouveau_drv.h"
 28#include "nouveau_pm.h"
 29
 30static void
 31nouveau_temp_vbios_parse(struct drm_device *dev, u8 *temp)
 32{
 33	struct drm_nouveau_private *dev_priv = dev->dev_private;
 34	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
 35	struct nouveau_pm_temp_sensor_constants *sensor = &pm->sensor_constants;
 36	struct nouveau_pm_threshold_temp *temps = &pm->threshold_temp;
 37	int i, headerlen, recordlen, entries;
 38
 39	if (!temp) {
 40		NV_DEBUG(dev, "temperature table pointer invalid\n");
 41		return;
 42	}
 43
 44	/* Set the default sensor's contants */
 45	sensor->offset_constant = 0;
 46	sensor->offset_mult = 0;
 47	sensor->offset_div = 1;
 48	sensor->slope_mult = 1;
 49	sensor->slope_div = 1;
 50
 51	/* Set the default temperature thresholds */
 52	temps->critical = 110;
 53	temps->down_clock = 100;
 54	temps->fan_boost = 90;
 55
 56	/* Set the known default values to setup the temperature sensor */
 57	if (dev_priv->card_type >= NV_40) {
 58		switch (dev_priv->chipset) {
 59		case 0x43:
 60			sensor->offset_mult = 32060;
 61			sensor->offset_div = 1000;
 62			sensor->slope_mult = 792;
 63			sensor->slope_div = 1000;
 64			break;
 65
 66		case 0x44:
 67		case 0x47:
 68		case 0x4a:
 69			sensor->offset_mult = 27839;
 70			sensor->offset_div = 1000;
 71			sensor->slope_mult = 780;
 72			sensor->slope_div = 1000;
 73			break;
 74
 75		case 0x46:
 76			sensor->offset_mult = -24775;
 77			sensor->offset_div = 100;
 78			sensor->slope_mult = 467;
 79			sensor->slope_div = 10000;
 80			break;
 81
 82		case 0x49:
 83			sensor->offset_mult = -25051;
 84			sensor->offset_div = 100;
 85			sensor->slope_mult = 458;
 86			sensor->slope_div = 10000;
 87			break;
 88
 89		case 0x4b:
 90			sensor->offset_mult = -24088;
 91			sensor->offset_div = 100;
 92			sensor->slope_mult = 442;
 93			sensor->slope_div = 10000;
 94			break;
 95
 96		case 0x50:
 97			sensor->offset_mult = -22749;
 98			sensor->offset_div = 100;
 99			sensor->slope_mult = 431;
100			sensor->slope_div = 10000;
101			break;
102
103		case 0x67:
104			sensor->offset_mult = -26149;
105			sensor->offset_div = 100;
106			sensor->slope_mult = 484;
107			sensor->slope_div = 10000;
108			break;
109		}
110	}
111
112	headerlen = temp[1];
113	recordlen = temp[2];
114	entries = temp[3];
115	temp = temp + headerlen;
116
117	/* Read the entries from the table */
118	for (i = 0; i < entries; i++) {
119		s16 value = ROM16(temp[1]);
120
121		switch (temp[0]) {
122		case 0x01:
123			if ((value & 0x8f) == 0)
124				sensor->offset_constant = (value >> 9) & 0x7f;
125			break;
126
127		case 0x04:
128			if ((value & 0xf00f) == 0xa000) /* core */
129				temps->critical = (value&0x0ff0) >> 4;
130			break;
131
132		case 0x07:
133			if ((value & 0xf00f) == 0xa000) /* core */
134				temps->down_clock = (value&0x0ff0) >> 4;
135			break;
136
137		case 0x08:
138			if ((value & 0xf00f) == 0xa000) /* core */
139				temps->fan_boost = (value&0x0ff0) >> 4;
140			break;
141
142		case 0x10:
143			sensor->offset_mult = value;
144			break;
145
146		case 0x11:
147			sensor->offset_div = value;
148			break;
149
150		case 0x12:
151			sensor->slope_mult = value;
152			break;
153
154		case 0x13:
155			sensor->slope_div = value;
156			break;
157		}
158		temp += recordlen;
159	}
160
161	nouveau_temp_safety_checks(dev);
162}
163
164static int
165nv40_sensor_setup(struct drm_device *dev)
166{
167	struct drm_nouveau_private *dev_priv = dev->dev_private;
168	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
169	struct nouveau_pm_temp_sensor_constants *sensor = &pm->sensor_constants;
170	s32 offset = sensor->offset_mult / sensor->offset_div;
171	s32 sensor_calibration;
172
173	/* set up the sensors */
174	sensor_calibration = 120 - offset - sensor->offset_constant;
175	sensor_calibration = sensor_calibration * sensor->slope_div /
176				sensor->slope_mult;
177
178	if (dev_priv->chipset >= 0x46)
179		sensor_calibration |= 0x80000000;
180	else
181		sensor_calibration |= 0x10000000;
182
183	nv_wr32(dev, 0x0015b0, sensor_calibration);
184
185	/* Wait for the sensor to update */
186	msleep(5);
187
188	/* read */
189	return nv_rd32(dev, 0x0015b4) & 0x1fff;
190}
191
192int
193nv40_temp_get(struct drm_device *dev)
194{
195	struct drm_nouveau_private *dev_priv = dev->dev_private;
196	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
197	struct nouveau_pm_temp_sensor_constants *sensor = &pm->sensor_constants;
198	int offset = sensor->offset_mult / sensor->offset_div;
199	int core_temp;
200
201	if (dev_priv->card_type >= NV_50) {
202		core_temp = nv_rd32(dev, 0x20008);
203	} else {
204		core_temp = nv_rd32(dev, 0x0015b4) & 0x1fff;
205		/* Setup the sensor if the temperature is 0 */
206		if (core_temp == 0)
207			core_temp = nv40_sensor_setup(dev);
208	}
209
210	core_temp = core_temp * sensor->slope_mult / sensor->slope_div;
211	core_temp = core_temp + offset + sensor->offset_constant;
212
213	return core_temp;
214}
215
216int
217nv84_temp_get(struct drm_device *dev)
218{
219	return nv_rd32(dev, 0x20400);
220}
221
222void
223nouveau_temp_safety_checks(struct drm_device *dev)
224{
225	struct drm_nouveau_private *dev_priv = dev->dev_private;
226	struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
227	struct nouveau_pm_threshold_temp *temps = &pm->threshold_temp;
228
229	if (temps->critical > 120)
230		temps->critical = 120;
231	else if (temps->critical < 80)
232		temps->critical = 80;
233
234	if (temps->down_clock > 110)
235		temps->down_clock = 110;
236	else if (temps->down_clock < 60)
237		temps->down_clock = 60;
238
239	if (temps->fan_boost > 100)
240		temps->fan_boost = 100;
241	else if (temps->fan_boost < 40)
242		temps->fan_boost = 40;
243}
244
245static bool
246probe_monitoring_device(struct nouveau_i2c_chan *i2c,
247			struct i2c_board_info *info)
248{
249	struct i2c_client *client;
250
251	request_module("%s%s", I2C_MODULE_PREFIX, info->type);
252
253	client = i2c_new_device(&i2c->adapter, info);
254	if (!client)
255		return false;
256
257	if (!client->driver || client->driver->detect(client, info)) {
258		i2c_unregister_device(client);
259		return false;
260	}
261
262	return true;
263}
264
265static void
266nouveau_temp_probe_i2c(struct drm_device *dev)
267{
268	struct drm_nouveau_private *dev_priv = dev->dev_private;
269	struct dcb_table *dcb = &dev_priv->vbios.dcb;
270	struct i2c_board_info info[] = {
271		{ I2C_BOARD_INFO("w83l785ts", 0x2d) },
272		{ I2C_BOARD_INFO("w83781d", 0x2d) },
273		{ I2C_BOARD_INFO("adt7473", 0x2e) },
274		{ I2C_BOARD_INFO("f75375", 0x2e) },
275		{ I2C_BOARD_INFO("lm99", 0x4c) },
276		{ }
277	};
278	int idx = (dcb->version >= 0x40 ?
279		   dcb->i2c_default_indices & 0xf : 2);
280
281	nouveau_i2c_identify(dev, "monitoring device", info,
282			     probe_monitoring_device, idx);
283}
284
285void
286nouveau_temp_init(struct drm_device *dev)
287{
288	struct drm_nouveau_private *dev_priv = dev->dev_private;
289	struct nvbios *bios = &dev_priv->vbios;
290	struct bit_entry P;
291	u8 *temp = NULL;
292
293	if (bios->type == NVBIOS_BIT) {
294		if (bit_table(dev, 'P', &P))
295			return;
296
297		if (P.version == 1)
298			temp = ROMPTR(bios, P.data[12]);
299		else if (P.version == 2)
300			temp = ROMPTR(bios, P.data[16]);
301		else
302			NV_WARN(dev, "unknown temp for BIT P %d\n", P.version);
303
304		nouveau_temp_vbios_parse(dev, temp);
305	}
306
307	nouveau_temp_probe_i2c(dev);
308}
309
310void
311nouveau_temp_fini(struct drm_device *dev)
312{
313
314}