提交 aa1b9b48 编写于 作者: M Martin Peres 提交者: Ben Skeggs

drm/nouveau/therm: move thermal-related functions to the therm subdev

It looks scary because of the size, but I tried to keep the differences minimal.
Further patches will fix the actual "driver" code and add new features.

v2: change filenames, split to submodules

v3: add a missing include

v4: Ben Skeggs <bskeggs@redhat.com>
- fixed set_defaults() to allow min_duty < 30 (thermal table will
  override this if it's actually necessary)
- fixed set_defaults() to not provide pwm_freq so nv4x (which only has
  pwm_div) can actually work.  the boards using pwm_freq will have a
  thermal table entry to provide us the value.
- removed unused files
Signed-off-by: NMartin Peres <martin.peres@labri.fr>
Signed-off-by: NBen Skeggs <bskeggs@redhat.com>
上级 d46497dc
......@@ -91,6 +91,12 @@ nouveau-y += core/subdev/mc/nvc0.o
nouveau-y += core/subdev/mxm/base.o
nouveau-y += core/subdev/mxm/mxms.o
nouveau-y += core/subdev/mxm/nv50.o
nouveau-y += core/subdev/therm/base.o
nouveau-y += core/subdev/therm/fan.o
nouveau-y += core/subdev/therm/ic.o
nouveau-y += core/subdev/therm/nv40.o
nouveau-y += core/subdev/therm/nv50.o
nouveau-y += core/subdev/therm/temp.o
nouveau-y += core/subdev/timer/base.o
nouveau-y += core/subdev/timer/nv04.o
nouveau-y += core/subdev/vm/base.o
......@@ -173,7 +179,7 @@ nouveau-y += nv50_crtc.o nv50_dac.o nv50_sor.o nv50_cursor.o
nouveau-y += nv50_evo.o
# drm/pm
nouveau-y += nouveau_pm.o nouveau_volt.o nouveau_perf.o nouveau_temp.o
nouveau-y += nouveau_pm.o nouveau_volt.o nouveau_perf.o
nouveau-y += nv04_pm.o nv40_pm.o nv50_pm.o nva3_pm.o nvc0_pm.o
nouveau-y += nouveau_mem.o
......
......@@ -22,7 +22,6 @@ enum nv_subdev_type {
NVDEV_SUBDEV_VM,
NVDEV_SUBDEV_BAR,
NVDEV_SUBDEV_VOLT,
NVDEV_SUBDEV_FAN0,
NVDEV_SUBDEV_THERM,
NVDEV_ENGINE_DMAOBJ,
NVDEV_ENGINE_FIFO,
......
#ifndef __NOUVEAU_THERM_H__
#define __NOUVEAU_THERM_H__
#include <core/device.h>
#include <core/subdev.h>
enum nouveau_therm_fan_mode {
FAN_CONTROL_NONE = 0,
FAN_CONTROL_MANUAL = 1,
FAN_CONTROL_NR,
};
enum nouveau_therm_attr_type {
NOUVEAU_THERM_ATTR_FAN_MIN_DUTY = 0,
NOUVEAU_THERM_ATTR_FAN_MAX_DUTY = 1,
NOUVEAU_THERM_ATTR_FAN_MODE = 2,
NOUVEAU_THERM_ATTR_THRS_FAN_BOOST = 10,
NOUVEAU_THERM_ATTR_THRS_FAN_BOOST_HYST = 11,
NOUVEAU_THERM_ATTR_THRS_DOWN_CLK = 12,
NOUVEAU_THERM_ATTR_THRS_DOWN_CLK_HYST = 13,
NOUVEAU_THERM_ATTR_THRS_CRITICAL = 14,
NOUVEAU_THERM_ATTR_THRS_CRITICAL_HYST = 15,
NOUVEAU_THERM_ATTR_THRS_SHUTDOWN = 16,
NOUVEAU_THERM_ATTR_THRS_SHUTDOWN_HYST = 17,
};
struct nouveau_therm {
struct nouveau_subdev base;
int (*fan_get)(struct nouveau_therm *);
int (*fan_set)(struct nouveau_therm *, int);
int (*fan_sense)(struct nouveau_therm *);
int (*temp_get)(struct nouveau_therm *);
int (*attr_get)(struct nouveau_therm *, enum nouveau_therm_attr_type);
int (*attr_set)(struct nouveau_therm *,
enum nouveau_therm_attr_type, int);
};
static inline struct nouveau_therm *
nouveau_therm(void *obj)
{
return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_THERM];
}
#define nouveau_therm_create(p,e,o,d) \
nouveau_subdev_create((p), (e), (o), 0, "THERM", "therm", d)
#define nouveau_therm_destroy(p) \
nouveau_subdev_destroy(&(p)->base)
#define _nouveau_therm_dtor _nouveau_subdev_dtor
extern struct nouveau_oclass nv40_therm_oclass;
extern struct nouveau_oclass nv50_therm_oclass;
#endif
......@@ -71,7 +71,6 @@ static const u64 disable_map[] = {
[NVDEV_SUBDEV_INSTMEM] = NV_DEVICE_DISABLE_CORE,
[NVDEV_SUBDEV_BAR] = NV_DEVICE_DISABLE_CORE,
[NVDEV_SUBDEV_VOLT] = NV_DEVICE_DISABLE_CORE,
[NVDEV_SUBDEV_FAN0] = NV_DEVICE_DISABLE_CORE,
[NVDEV_SUBDEV_CLOCK] = NV_DEVICE_DISABLE_CORE,
[NVDEV_SUBDEV_THERM] = NV_DEVICE_DISABLE_CORE,
[NVDEV_ENGINE_DMAOBJ] = NV_DEVICE_DISABLE_CORE,
......
......@@ -27,6 +27,7 @@
#include <subdev/gpio.h>
#include <subdev/i2c.h>
#include <subdev/clock.h>
#include <subdev/therm.h>
#include <subdev/devinit.h>
#include <subdev/mc.h>
#include <subdev/timer.h>
......
......@@ -27,6 +27,7 @@
#include <subdev/gpio.h>
#include <subdev/i2c.h>
#include <subdev/clock.h>
#include <subdev/therm.h>
#include <subdev/devinit.h>
#include <subdev/mc.h>
#include <subdev/timer.h>
......@@ -51,6 +52,7 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
......@@ -70,6 +72,7 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
......@@ -89,6 +92,7 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
......@@ -108,6 +112,7 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
......@@ -127,6 +132,7 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
......@@ -146,6 +152,7 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
......@@ -165,6 +172,7 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
......@@ -184,6 +192,7 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv04_mc_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
......@@ -203,6 +212,7 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
......@@ -222,6 +232,7 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
......@@ -241,6 +252,7 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
......@@ -260,6 +272,7 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
......@@ -279,6 +292,7 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
......@@ -298,6 +312,7 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
......@@ -317,6 +332,7 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
......@@ -336,6 +352,7 @@ nv40_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv10_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv44_mc_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
......
......@@ -27,6 +27,7 @@
#include <subdev/gpio.h>
#include <subdev/i2c.h>
#include <subdev/clock.h>
#include <subdev/therm.h>
#include <subdev/mxm.h>
#include <subdev/devinit.h>
#include <subdev/mc.h>
......@@ -58,6 +59,7 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass;
......@@ -79,6 +81,7 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass;
......@@ -103,6 +106,7 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass;
......@@ -127,6 +131,7 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass;
......@@ -151,6 +156,7 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass;
......@@ -175,6 +181,7 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv50_mc_oclass;
......@@ -199,6 +206,7 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass;
......@@ -223,6 +231,7 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass;
......@@ -247,6 +256,7 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass;
......@@ -271,6 +281,7 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv50_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass;
......@@ -295,6 +306,7 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass;
......@@ -320,6 +332,7 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass;
......@@ -344,6 +357,7 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass;
......@@ -368,6 +382,7 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass;
......
......@@ -27,6 +27,7 @@
#include <subdev/gpio.h>
#include <subdev/i2c.h>
#include <subdev/clock.h>
#include <subdev/therm.h>
#include <subdev/mxm.h>
#include <subdev/devinit.h>
#include <subdev/mc.h>
......@@ -57,6 +58,7 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
......@@ -83,6 +85,7 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
......@@ -109,6 +112,7 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
......@@ -135,6 +139,7 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
......@@ -161,6 +166,7 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
......@@ -187,6 +193,7 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
......@@ -213,6 +220,7 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_GPIO ] = &nv50_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
......@@ -239,6 +247,7 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_GPIO ] = &nvd0_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
......
......@@ -27,6 +27,7 @@
#include <subdev/gpio.h>
#include <subdev/i2c.h>
#include <subdev/clock.h>
#include <subdev/therm.h>
#include <subdev/mxm.h>
#include <subdev/devinit.h>
#include <subdev/mc.h>
......@@ -55,6 +56,7 @@ nve0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_GPIO ] = &nvd0_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
......@@ -79,6 +81,7 @@ nve0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_GPIO ] = &nvd0_gpio_oclass;
device->oclass[NVDEV_SUBDEV_I2C ] = &nouveau_i2c_oclass;
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
......
/*
* Copyright 2012 The Nouveau community
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Martin Peres
*/
#include <core/object.h>
#include <core/device.h>
#include <subdev/bios.h>
#include "priv.h"
int
nouveau_therm_attr_get(struct nouveau_therm *therm,
enum nouveau_therm_attr_type type)
{
struct nouveau_therm_priv *priv = (void *)therm;
switch (type) {
case NOUVEAU_THERM_ATTR_FAN_MIN_DUTY:
return priv->bios_fan.min_duty;
case NOUVEAU_THERM_ATTR_FAN_MAX_DUTY:
return priv->bios_fan.max_duty;
case NOUVEAU_THERM_ATTR_THRS_FAN_BOOST:
return priv->bios_sensor.thrs_fan_boost.temp;
case NOUVEAU_THERM_ATTR_THRS_FAN_BOOST_HYST:
return priv->bios_sensor.thrs_fan_boost.hysteresis;
case NOUVEAU_THERM_ATTR_THRS_DOWN_CLK:
return priv->bios_sensor.thrs_down_clock.temp;
case NOUVEAU_THERM_ATTR_THRS_DOWN_CLK_HYST:
return priv->bios_sensor.thrs_down_clock.hysteresis;
case NOUVEAU_THERM_ATTR_THRS_CRITICAL:
return priv->bios_sensor.thrs_critical.temp;
case NOUVEAU_THERM_ATTR_THRS_CRITICAL_HYST:
return priv->bios_sensor.thrs_critical.hysteresis;
case NOUVEAU_THERM_ATTR_THRS_SHUTDOWN:
return priv->bios_sensor.thrs_shutdown.temp;
case NOUVEAU_THERM_ATTR_THRS_SHUTDOWN_HYST:
return priv->bios_sensor.thrs_shutdown.hysteresis;
}
return -EINVAL;
}
int
nouveau_therm_attr_set(struct nouveau_therm *therm,
enum nouveau_therm_attr_type type, int value)
{
struct nouveau_therm_priv *priv = (void *)therm;
switch (type) {
case NOUVEAU_THERM_ATTR_FAN_MIN_DUTY:
if (value < 0)
value = 0;
if (value > priv->bios_fan.max_duty)
value = priv->bios_fan.max_duty;
priv->bios_fan.min_duty = value;
return 0;
case NOUVEAU_THERM_ATTR_FAN_MAX_DUTY:
if (value < 0)
value = 0;
if (value < priv->bios_fan.min_duty)
value = priv->bios_fan.min_duty;
priv->bios_fan.max_duty = value;
return 0;
case NOUVEAU_THERM_ATTR_THRS_FAN_BOOST:
priv->bios_sensor.thrs_fan_boost.temp = value;
return 0;
case NOUVEAU_THERM_ATTR_THRS_FAN_BOOST_HYST:
priv->bios_sensor.thrs_fan_boost.hysteresis = value;
return 0;
case NOUVEAU_THERM_ATTR_THRS_DOWN_CLK:
priv->bios_sensor.thrs_down_clock.temp = value;
return 0;
case NOUVEAU_THERM_ATTR_THRS_DOWN_CLK_HYST:
priv->bios_sensor.thrs_down_clock.hysteresis = value;
return 0;
case NOUVEAU_THERM_ATTR_THRS_CRITICAL:
priv->bios_sensor.thrs_critical.temp = value;
return 0;
case NOUVEAU_THERM_ATTR_THRS_CRITICAL_HYST:
priv->bios_sensor.thrs_critical.hysteresis = value;
return 0;
case NOUVEAU_THERM_ATTR_THRS_SHUTDOWN:
priv->bios_sensor.thrs_shutdown.temp = value;
return 0;
case NOUVEAU_THERM_ATTR_THRS_SHUTDOWN_HYST:
priv->bios_sensor.thrs_shutdown.hysteresis = value;
return 0;
}
return -EINVAL;
}
int
nouveau_therm_init(struct nouveau_object *object)
{
struct nouveau_therm *therm = (void *)object;
struct nouveau_therm_priv *priv = (void *)therm;
int ret;
ret = nouveau_subdev_init(&therm->base);
if (ret)
return ret;
if (priv->fan.percent >= 0)
therm->fan_set(therm, priv->fan.percent);
return 0;
}
int
nouveau_therm_fini(struct nouveau_object *object, bool suspend)
{
struct nouveau_therm *therm = (void *)object;
struct nouveau_therm_priv *priv = (void *)therm;
priv->fan.percent = therm->fan_get(therm);
return nouveau_subdev_fini(&therm->base, suspend);
}
/*
* Copyright 2012 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
* Martin Peres
*/
#include "priv.h"
#include <core/object.h>
#include <core/device.h>
#include <subdev/gpio.h>
#include <subdev/timer.h>
int
nouveau_therm_fan_get(struct nouveau_therm *therm)
{
struct nouveau_therm_priv *priv = (void *)therm;
struct nouveau_gpio *gpio = nouveau_gpio(therm);
struct dcb_gpio_func func;
int card_type = nv_device(therm)->card_type;
u32 divs, duty;
int ret;
if (!priv->fan.pwm_get)
return -ENODEV;
ret = gpio->find(gpio, 0, DCB_GPIO_PWM_FAN, 0xff, &func);
if (ret == 0) {
ret = priv->fan.pwm_get(therm, func.line, &divs, &duty);
if (ret == 0 && divs) {
divs = max(divs, duty);
if (card_type <= NV_40 || (func.log[0] & 1))
duty = divs - duty;
return (duty * 100) / divs;
}
return gpio->get(gpio, 0, func.func, func.line) * 100;
}
return -ENODEV;
}
int
nouveau_therm_fan_set(struct nouveau_therm *therm, int percent)
{
struct nouveau_therm_priv *priv = (void *)therm;
struct nouveau_gpio *gpio = nouveau_gpio(therm);
struct dcb_gpio_func func;
int card_type = nv_device(therm)->card_type;
u32 divs, duty;
int ret;
if (!priv->fan.pwm_set)
return -ENODEV;
if (percent < priv->bios_fan.min_duty)
percent = priv->bios_fan.min_duty;
if (percent > priv->bios_fan.max_duty)
percent = priv->bios_fan.max_duty;
ret = gpio->find(gpio, 0, DCB_GPIO_PWM_FAN, 0xff, &func);
if (ret == 0) {
divs = priv->bios_perf_fan.pwm_divisor;
if (priv->bios_fan.pwm_freq) {
/*XXX: PNVIO clock more than likely... */
divs = 135000 /priv->bios_fan.pwm_freq;
if (nv_device(therm)->chipset < 0xa3)
divs /= 4;
}
duty = ((divs * percent) + 99) / 100;
if (card_type <= NV_40 || (func.log[0] & 1))
duty = divs - duty;
ret = priv->fan.pwm_set(therm, func.line, divs, duty);
return ret;
}
return -ENODEV;
}
int
nouveau_therm_fan_sense(struct nouveau_therm *therm)
{
struct nouveau_timer *ptimer = nouveau_timer(therm);
struct nouveau_gpio *gpio = nouveau_gpio(therm);
struct dcb_gpio_func func;
u32 cycles, cur, prev;
u64 start;
if (gpio->find(gpio, 0, DCB_GPIO_FAN_SENSE, 0xff, &func))
return -ENODEV;
/* Monitor the GPIO input 0x3b for 250ms.
* When the fan spins, it changes the value of GPIO FAN_SENSE.
* We get 4 changes (0 -> 1 -> 0 -> 1 -> [...]) per complete rotation.
*/
start = ptimer->read(ptimer);
prev = gpio->get(gpio, 0, func.func, func.line);
cycles = 0;
do {
cur = gpio->get(gpio, 0, func.func, func.line);
if (prev != cur) {
cycles++;
prev = cur;
}
usleep_range(500, 1000); /* supports 0 < rpm < 7500 */
} while (ptimer->read(ptimer) - start < 250000000);
/* interpolate to get rpm */
return cycles / 4 * 4 * 60;
}
static void
nouveau_therm_fan_set_defaults(struct nouveau_therm *therm)
{
struct nouveau_therm_priv *priv = (void *)therm;
priv->bios_fan.pwm_freq = 0;
priv->bios_fan.min_duty = 0;
priv->bios_fan.max_duty = 100;
}
static void
nouveau_therm_fan_safety_checks(struct nouveau_therm *therm)
{
struct nouveau_therm_priv *priv = (void *)therm;
if (priv->bios_fan.min_duty > 100)
priv->bios_fan.min_duty = 100;
if (priv->bios_fan.max_duty > 100)
priv->bios_fan.max_duty = 100;
if (priv->bios_fan.min_duty > priv->bios_fan.max_duty)
priv->bios_fan.min_duty = priv->bios_fan.max_duty;
}
int
nouveau_therm_fan_ctor(struct nouveau_therm *therm)
{
struct nouveau_therm_priv *priv = (void *)therm;
struct nouveau_bios *bios = nouveau_bios(therm);
nouveau_therm_fan_set_defaults(therm);
nvbios_perf_fan_parse(bios, &priv->bios_perf_fan);
if (nvbios_therm_fan_parse(bios, &priv->bios_fan))
nv_error(therm, "parsing the thermal table failed\n");
nouveau_therm_fan_safety_checks(therm);
return 0;
}
/*
* Copyright 2010 PathScale inc.
* Copyright 2012 Nouveau community
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
......@@ -22,97 +22,16 @@
* Authors: Martin Peres
*/
#include <linux/module.h>
#include "drmP.h"
#include "nouveau_drm.h"
#include "nouveau_pm.h"
#include "priv.h"
#include <subdev/i2c.h>
#include <subdev/bios/therm.h>
#include <subdev/bios/extdev.h>
static int
nv40_sensor_setup(struct drm_device *dev)
{
struct nouveau_device *device = nouveau_dev(dev);
struct nouveau_drm *drm = nouveau_drm(dev);
/* enable ADC readout and disable the ALARM threshold */
if (nv_device(drm->device)->chipset >= 0x46) {
nv_mask(device, 0x15b8, 0x80000000, 0);
nv_wr32(device, 0x15b0, 0x80003fff);
return nv_rd32(device, 0x15b4) & 0x3fff;
} else {
nv_wr32(device, 0x15b0, 0xff);
return nv_rd32(device, 0x15b4) & 0xff;
}
}
int
nv40_temp_get(struct drm_device *dev)
{
struct nouveau_device *device = nouveau_dev(dev);
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_pm *pm = nouveau_pm(dev);
struct nouveau_pm_temp_sensor_constants *sensor = &pm->sensor_constants;
int core_temp;
if (nv_device(drm->device)->chipset >= 0x46) {
nv_wr32(device, 0x15b0, 0x80003fff);
core_temp = nv_rd32(device, 0x15b4) & 0x3fff;
} else {
nv_wr32(device, 0x15b0, 0xff);
core_temp = nv_rd32(device, 0x15b4) & 0xff;
}
/* Setup the sensor if the temperature is 0 */
if (core_temp == 0)
core_temp = nv40_sensor_setup(dev);
if (sensor->slope_div == 0)
sensor->slope_div = 1;
if (sensor->offset_div == 0)
sensor->offset_div = 1;
if (sensor->slope_mult < 1)
sensor->slope_mult = 1;
core_temp = core_temp * sensor->slope_mult / sensor->slope_div;
core_temp = core_temp + sensor->offset_mult / sensor->offset_div;
core_temp = core_temp + sensor->offset_constant - 8;
return core_temp;
}
int
nv84_temp_get(struct drm_device *dev)
{
struct nouveau_device *device = nouveau_dev(dev);
return nv_rd32(device, 0x20400);
}
void
nouveau_temp_safety_checks(struct drm_device *dev)
{
struct nouveau_pm *pm = nouveau_pm(dev);
struct nouveau_pm_threshold_temp *temps = &pm->threshold_temp;
if (temps->critical > 120)
temps->critical = 120;
else if (temps->critical < 80)
temps->critical = 80;
if (temps->down_clock > 110)
temps->down_clock = 110;
else if (temps->down_clock < 60)
temps->down_clock = 60;
}
static bool
probe_monitoring_device(struct nouveau_i2c_port *i2c,
struct i2c_board_info *info)
{
struct nouveau_therm_priv *priv = (void *)nouveau_therm(i2c->i2c);
struct i2c_client *client;
request_module("%s%s", I2C_MODULE_PREFIX, info->type);
......@@ -126,15 +45,20 @@ probe_monitoring_device(struct nouveau_i2c_port *i2c,
return false;
}
nv_info(priv,
"Found an %s at address 0x%x (controlled by lm_sensors)\n",
info->type, info->addr);
priv->ic = client;
return true;
}
static void
nouveau_temp_probe_i2c(struct drm_device *dev)
void
nouveau_therm_ic_ctor(struct nouveau_therm *therm)
{
struct nouveau_device *device = nouveau_dev(dev);
struct nouveau_bios *bios = nouveau_bios(device);
struct nouveau_i2c *i2c = nouveau_i2c(device);
struct nouveau_therm_priv *priv = (void *)therm;
struct nouveau_bios *bios = nouveau_bios(therm);
struct nouveau_i2c *i2c = nouveau_i2c(therm);
struct nvbios_extdev_func extdev_entry;
struct i2c_board_info info[] = {
{ I2C_BOARD_INFO("w83l785ts", 0x2d) },
......@@ -166,8 +90,9 @@ nouveau_temp_probe_i2c(struct drm_device *dev)
{ }
};
if (i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device",
board, probe_monitoring_device))
i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device",
board, probe_monitoring_device);
if (priv->ic)
return;
}
......@@ -177,8 +102,9 @@ nouveau_temp_probe_i2c(struct drm_device *dev)
{ }
};
if (i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device",
board, probe_monitoring_device))
i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device",
board, probe_monitoring_device);
if (priv->ic)
return;
}
......@@ -188,50 +114,3 @@ nouveau_temp_probe_i2c(struct drm_device *dev)
i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device", info,
probe_monitoring_device);
}
void
nouveau_temp_init(struct drm_device *dev)
{
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_device *device = nv_device(drm->device);
struct nouveau_bios *bios = nouveau_bios(device);
struct nouveau_pm *pm = nouveau_pm(dev);
struct nouveau_pm_temp_sensor_constants *sensor = &pm->sensor_constants;
struct nouveau_pm_threshold_temp *temps = &pm->threshold_temp;
struct nvbios_therm_sensor bios_sensor;
struct nvbios_therm_fan bios_fan;
/* store some safe defaults */
sensor->offset_constant = 0;
sensor->offset_mult = 0;
sensor->offset_div = 1;
sensor->slope_mult = 1;
sensor->slope_div = 1;
if (!nvbios_therm_sensor_parse(bios, NVBIOS_THERM_DOMAIN_CORE,
&bios_sensor)) {
sensor->slope_mult = bios_sensor.slope_mult;
sensor->slope_div = bios_sensor.slope_div;
sensor->offset_mult = bios_sensor.offset_num;
sensor->offset_div = bios_sensor.offset_den;
sensor->offset_constant = bios_sensor.offset_constant;
temps->down_clock = bios_sensor.thrs_down_clock.temp;
temps->critical = bios_sensor.thrs_critical.temp;
}
if (nvbios_therm_fan_parse(bios, &bios_fan)) {
pm->fan.min_duty = bios_fan.min_duty;
pm->fan.max_duty = bios_fan.max_duty;
pm->fan.pwm_freq = bios_fan.pwm_freq;
}
nouveau_temp_safety_checks(dev);
nouveau_temp_probe_i2c(dev);
}
void
nouveau_temp_fini(struct drm_device *dev)
{
}
/*
* Copyright 2012 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
* Martin Peres
*/
#include "priv.h"
static int
nv40_sensor_setup(struct nouveau_therm *therm)
{
struct nouveau_device *device = nv_device(therm);
/* enable ADC readout and disable the ALARM threshold */
if (device->chipset >= 0x46) {
nv_mask(therm, 0x15b8, 0x80000000, 0);
nv_wr32(therm, 0x15b0, 0x80003fff);
return nv_rd32(therm, 0x15b4) & 0x3fff;
} else {
nv_wr32(therm, 0x15b0, 0xff);
return nv_rd32(therm, 0x15b4) & 0xff;
}
}
static int
nv40_temp_get(struct nouveau_therm *therm)
{
struct nouveau_therm_priv *priv = (void *)therm;
struct nouveau_device *device = nv_device(therm);
struct nvbios_therm_sensor *sensor = &priv->bios_sensor;
int core_temp;
if (device->chipset >= 0x46) {
nv_wr32(therm, 0x15b0, 0x80003fff);
core_temp = nv_rd32(therm, 0x15b4) & 0x3fff;
} else {
nv_wr32(therm, 0x15b0, 0xff);
core_temp = nv_rd32(therm, 0x15b4) & 0xff;
}
/* Setup the sensor if the temperature is 0 */
if (core_temp == 0)
core_temp = nv40_sensor_setup(therm);
if (sensor->slope_div == 0)
sensor->slope_div = 1;
if (sensor->offset_den == 0)
sensor->offset_den = 1;
if (sensor->slope_mult < 1)
sensor->slope_mult = 1;
core_temp = core_temp * sensor->slope_mult / sensor->slope_div;
core_temp = core_temp + sensor->offset_num / sensor->offset_den;
core_temp = core_temp + sensor->offset_constant - 8;
return core_temp;
}
int
nv40_fan_pwm_get(struct nouveau_therm *therm, int line, u32 *divs, u32 *duty)
{
if (line == 2) {
u32 reg = nv_rd32(therm, 0x0010f0);
if (reg & 0x80000000) {
*duty = (reg & 0x7fff0000) >> 16;
*divs = (reg & 0x00007fff);
return 0;
}
} else
if (line == 9) {
u32 reg = nv_rd32(therm, 0x0015f4);
if (reg & 0x80000000) {
*divs = nv_rd32(therm, 0x0015f8);
*duty = (reg & 0x7fffffff);
return 0;
}
} else {
nv_error(therm, "unknown pwm ctrl for gpio %d\n", line);
return -ENODEV;
}
return -EINVAL;
}
int
nv40_fan_pwm_set(struct nouveau_therm *therm, int line, u32 divs, u32 duty)
{
if (line == 2) {
nv_wr32(therm, 0x0010f0, 0x80000000 | (duty << 16) | divs);
} else
if (line == 9) {
nv_wr32(therm, 0x0015f8, divs);
nv_wr32(therm, 0x0015f4, duty | 0x80000000);
} else {
nv_error(therm, "unknown pwm ctrl for gpio %d\n", line);
return -ENODEV;
}
return 0;
}
static int
nv40_therm_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nouveau_therm_priv *priv;
struct nouveau_therm *therm;
int ret;
ret = nouveau_therm_create(parent, engine, oclass, &priv);
*pobject = nv_object(priv);
therm = (void *) priv;
if (ret)
return ret;
nouveau_therm_ic_ctor(therm);
nouveau_therm_sensor_ctor(therm);
nouveau_therm_fan_ctor(therm);
priv->fan.pwm_get = nv40_fan_pwm_get;
priv->fan.pwm_set = nv40_fan_pwm_set;
therm->temp_get = nv40_temp_get;
therm->fan_get = nouveau_therm_fan_get;
therm->fan_set = nouveau_therm_fan_set;
therm->fan_sense = nouveau_therm_fan_sense;
therm->attr_get = nouveau_therm_attr_get;
therm->attr_set = nouveau_therm_attr_set;
return 0;
}
struct nouveau_oclass
nv40_therm_oclass = {
.handle = NV_SUBDEV(THERM, 0x40),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv40_therm_ctor,
.dtor = _nouveau_therm_dtor,
.init = nouveau_therm_init,
.fini = nouveau_therm_fini,
},
};
\ No newline at end of file
/*
* Copyright 2012 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
* Martin Peres
*/
#include "priv.h"
static int
pwm_info(struct nouveau_therm *therm, int *line, int *ctrl, int *indx)
{
if (*line == 0x04) {
*ctrl = 0x00e100;
*line = 4;
*indx = 0;
} else
if (*line == 0x09) {
*ctrl = 0x00e100;
*line = 9;
*indx = 1;
} else
if (*line == 0x10) {
*ctrl = 0x00e28c;
*line = 0;
*indx = 0;
} else {
nv_error(therm, "unknown pwm ctrl for gpio %d\n", *line);
return -ENODEV;
}
return 0;
}
int
nv50_fan_pwm_get(struct nouveau_therm *therm, int line, u32 *divs, u32 *duty)
{
int ctrl, id, ret = pwm_info(therm, &line, &ctrl, &id);
if (ret)
return ret;
if (nv_rd32(therm, ctrl) & (1 << line)) {
*divs = nv_rd32(therm, 0x00e114 + (id * 8));
*duty = nv_rd32(therm, 0x00e118 + (id * 8));
return 0;
}
return -EINVAL;
}
int
nv50_fan_pwm_set(struct nouveau_therm *therm, int line, u32 divs, u32 duty)
{
int ctrl, id, ret = pwm_info(therm, &line, &ctrl, &id);
if (ret)
return ret;
nv_mask(therm, ctrl, 0x00010001 << line, 0x00000001 << line);
nv_wr32(therm, 0x00e114 + (id * 8), divs);
nv_wr32(therm, 0x00e118 + (id * 8), duty | 0x80000000);
return 0;
}
int
nv50_temp_get(struct nouveau_therm *therm)
{
return nv_rd32(therm, 0x20400);
}
static int
nv50_therm_ctor(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
struct nouveau_therm_priv *priv;
struct nouveau_therm *therm;
int ret;
ret = nouveau_therm_create(parent, engine, oclass, &priv);
*pobject = nv_object(priv);
therm = (void *) priv;
if (ret)
return ret;
nouveau_therm_ic_ctor(therm);
nouveau_therm_sensor_ctor(therm);
nouveau_therm_fan_ctor(therm);
priv->fan.pwm_get = nv50_fan_pwm_get;
priv->fan.pwm_set = nv50_fan_pwm_set;
therm->temp_get = nv50_temp_get;
therm->fan_get = nouveau_therm_fan_get;
therm->fan_set = nouveau_therm_fan_set;
therm->fan_sense = nouveau_therm_fan_sense;
therm->attr_get = nouveau_therm_attr_get;
therm->attr_set = nouveau_therm_attr_set;
return 0;
}
struct nouveau_oclass
nv50_therm_oclass = {
.handle = NV_SUBDEV(THERM, 0x50),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv50_therm_ctor,
.dtor = _nouveau_therm_dtor,
.init = nouveau_therm_init,
.fini = nouveau_therm_fini,
},
};
/*
* Copyright 2012 The Nouveau community
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Martin Peres
*/
#include <subdev/therm.h>
#include <subdev/bios/extdev.h>
#include <subdev/bios/perf.h>
#include <subdev/bios/therm.h>
struct nouveau_therm_priv {
struct nouveau_therm base;
/* bios */
struct nvbios_therm_sensor bios_sensor;
struct nvbios_therm_fan bios_fan;
struct nvbios_perf_fan bios_perf_fan;
/* fan priv */
struct {
int percent;
int (*pwm_get)(struct nouveau_therm *, int line, u32*, u32*);
int (*pwm_set)(struct nouveau_therm *, int line, u32, u32);
} fan;
/* ic */
struct i2c_client *ic;
};
int nouveau_therm_init(struct nouveau_object *object);
int nouveau_therm_fini(struct nouveau_object *object, bool suspend);
int nouveau_therm_attr_get(struct nouveau_therm *therm,
enum nouveau_therm_attr_type type);
int nouveau_therm_attr_set(struct nouveau_therm *therm,
enum nouveau_therm_attr_type type, int value);
void nouveau_therm_ic_ctor(struct nouveau_therm *therm);
int nouveau_therm_sensor_ctor(struct nouveau_therm *therm);
int nouveau_therm_fan_ctor(struct nouveau_therm *therm);
int nouveau_therm_fan_get(struct nouveau_therm *therm);
int nouveau_therm_fan_set(struct nouveau_therm *therm, int percent);
int nouveau_therm_fan_sense(struct nouveau_therm *therm);
/*
* Copyright 2012 The Nouveau community
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Martin Peres
*/
#include "priv.h"
#include <core/object.h>
#include <core/device.h>
#include <subdev/bios.h>
static void
nouveau_therm_temp_set_defaults(struct nouveau_therm *therm)
{
struct nouveau_therm_priv *priv = (void *)therm;
priv->bios_sensor.slope_mult = 1;
priv->bios_sensor.slope_div = 1;
priv->bios_sensor.offset_num = 0;
priv->bios_sensor.offset_den = 1;
priv->bios_sensor.offset_constant = 0;
priv->bios_sensor.thrs_fan_boost.temp = 90;
priv->bios_sensor.thrs_fan_boost.hysteresis = 3;
priv->bios_sensor.thrs_down_clock.temp = 95;
priv->bios_sensor.thrs_down_clock.hysteresis = 3;
priv->bios_sensor.thrs_critical.temp = 105;
priv->bios_sensor.thrs_critical.hysteresis = 5;
priv->bios_sensor.thrs_shutdown.temp = 135;
priv->bios_sensor.thrs_shutdown.hysteresis = 5; /*not that it matters */
}
static void
nouveau_therm_temp_safety_checks(struct nouveau_therm *therm)
{
struct nouveau_therm_priv *priv = (void *)therm;
if (!priv->bios_sensor.slope_div)
priv->bios_sensor.slope_div = 1;
if (!priv->bios_sensor.offset_den)
priv->bios_sensor.offset_den = 1;
}
int
nouveau_therm_sensor_ctor(struct nouveau_therm *therm)
{
struct nouveau_therm_priv *priv = (void *)therm;
struct nouveau_bios *bios = nouveau_bios(therm);
nouveau_therm_temp_set_defaults(therm);
if (nvbios_therm_sensor_parse(bios, NVBIOS_THERM_DOMAIN_CORE,
&priv->bios_sensor))
nv_error(therm, "nvbios_therm_sensor_parse failed\n");
nouveau_therm_temp_safety_checks(therm);
return 0;
}
......@@ -304,8 +304,6 @@ nouveau_perf_init(struct drm_device *dev)
}
perf = nouveau_perf_table(dev, &ver);
if (ver >= 0x20 && ver < 0x40)
pm->fan.pwm_divisor = ROM16(perf[6]);
while ((perf = nouveau_perf_entry(dev, ++i, &ver, &hdr, &cnt, &len))) {
struct nouveau_pm_level *perflvl = &pm->perflvl[pm->nr_perflvl];
......
......@@ -34,9 +34,9 @@
#include "nouveau_drm.h"
#include "nouveau_pm.h"
#include <subdev/bios/gpio.h>
#include <subdev/gpio.h>
#include <subdev/timer.h>
#include <subdev/therm.h>
MODULE_PARM_DESC(perflvl, "Performance level (default: boot)");
static char *nouveau_perflvl;
......@@ -46,87 +46,22 @@ MODULE_PARM_DESC(perflvl_wr, "Allow perflvl changes (warning: dangerous!)");
static int nouveau_perflvl_wr;
module_param_named(perflvl_wr, nouveau_perflvl_wr, int, 0400);
static int
nouveau_pwmfan_get(struct drm_device *dev)
{
struct nouveau_pm *pm = nouveau_pm(dev);
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_device *device = nv_device(drm->device);
struct nouveau_gpio *gpio = nouveau_gpio(device);
struct dcb_gpio_func func;
u32 divs, duty;
int ret;
if (!pm->pwm_get)
return -ENODEV;
ret = gpio->find(gpio, 0, DCB_GPIO_PWM_FAN, 0xff, &func);
if (ret == 0) {
ret = pm->pwm_get(dev, func.line, &divs, &duty);
if (ret == 0 && divs) {
divs = max(divs, duty);
if (device->card_type <= NV_40 || (func.log[0] & 1))
duty = divs - duty;
return (duty * 100) / divs;
}
return gpio->get(gpio, 0, func.func, func.line) * 100;
}
return -ENODEV;
}
static int
nouveau_pwmfan_set(struct drm_device *dev, int percent)
{
struct nouveau_pm *pm = nouveau_pm(dev);
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_device *device = nv_device(drm->device);
struct nouveau_gpio *gpio = nouveau_gpio(device);
struct dcb_gpio_func func;
u32 divs, duty;
int ret;
if (!pm->pwm_set)
return -ENODEV;
ret = gpio->find(gpio, 0, DCB_GPIO_PWM_FAN, 0xff, &func);
if (ret == 0) {
divs = pm->fan.pwm_divisor;
if (pm->fan.pwm_freq) {
/*XXX: PNVIO clock more than likely... */
divs = 135000 / pm->fan.pwm_freq;
if (nv_device(drm->device)->chipset < 0xa3)
divs /= 4;
}
duty = ((divs * percent) + 99) / 100;
if (device->card_type <= NV_40 || (func.log[0] & 1))
duty = divs - duty;
ret = pm->pwm_set(dev, func.line, divs, duty);
if (!ret)
pm->fan.percent = percent;
return ret;
}
return -ENODEV;
}
static int
nouveau_pm_perflvl_aux(struct drm_device *dev, struct nouveau_pm_level *perflvl,
struct nouveau_pm_level *a, struct nouveau_pm_level *b)
{
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_pm *pm = nouveau_pm(dev);
struct nouveau_therm *therm = nouveau_therm(drm);
int ret;
/*XXX: not on all boards, we should control based on temperature
* on recent boards.. or maybe on some other factor we don't
* know about?
*/
if (a->fanspeed && b->fanspeed && b->fanspeed > a->fanspeed) {
ret = nouveau_pwmfan_set(dev, perflvl->fanspeed);
if (therm && therm->fan_set &&
a->fanspeed && b->fanspeed && b->fanspeed > a->fanspeed) {
ret = therm->fan_set(therm, perflvl->fanspeed);
if (ret && ret != -ENODEV) {
NV_ERROR(drm, "fanspeed set failed: %d\n", ret);
return ret;
......@@ -291,7 +226,9 @@ const struct nouveau_pm_profile_func nouveau_pm_static_profile_func = {
static int
nouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl)
{
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_pm *pm = nouveau_pm(dev);
struct nouveau_therm *therm = nouveau_therm(drm->device);
int ret;
memset(perflvl, 0, sizeof(*perflvl));
......@@ -310,9 +247,11 @@ nouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl)
}
}
ret = nouveau_pwmfan_get(dev);
if (ret > 0)
perflvl->fanspeed = ret;
if (therm && therm->fan_get) {
ret = therm->fan_get(therm);
if (ret >= 0)
perflvl->fanspeed = ret;
}
nouveau_mem_timing_read(dev, &perflvl->timing);
return 0;
......@@ -462,9 +401,10 @@ static ssize_t
nouveau_hwmon_show_temp(struct device *d, struct device_attribute *a, char *buf)
{
struct drm_device *dev = dev_get_drvdata(d);
struct nouveau_pm *pm = nouveau_pm(dev);
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_therm *therm = nouveau_therm(drm->device);
return snprintf(buf, PAGE_SIZE, "%d\n", pm->temp_get(dev)*1000);
return snprintf(buf, PAGE_SIZE, "%d\n", therm->temp_get(therm) * 1000);
}
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, nouveau_hwmon_show_temp,
NULL, 0);
......@@ -473,26 +413,25 @@ static ssize_t
nouveau_hwmon_max_temp(struct device *d, struct device_attribute *a, char *buf)
{
struct drm_device *dev = dev_get_drvdata(d);
struct nouveau_pm *pm = nouveau_pm(dev);
struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp;
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_therm *therm = nouveau_therm(drm->device);
return snprintf(buf, PAGE_SIZE, "%d\n", temp->down_clock*1000);
return snprintf(buf, PAGE_SIZE, "%d\n",
therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_DOWN_CLK) * 1000);
}
static ssize_t
nouveau_hwmon_set_max_temp(struct device *d, struct device_attribute *a,
const char *buf, size_t count)
{
struct drm_device *dev = dev_get_drvdata(d);
struct nouveau_pm *pm = nouveau_pm(dev);
struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp;
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_therm *therm = nouveau_therm(drm->device);
long value;
if (kstrtol(buf, 10, &value) == -EINVAL)
return count;
temp->down_clock = value/1000;
nouveau_temp_safety_checks(dev);
therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_DOWN_CLK, value / 1000);
return count;
}
......@@ -505,10 +444,11 @@ nouveau_hwmon_critical_temp(struct device *d, struct device_attribute *a,
char *buf)
{
struct drm_device *dev = dev_get_drvdata(d);
struct nouveau_pm *pm = nouveau_pm(dev);
struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp;
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_therm *therm = nouveau_therm(drm->device);
return snprintf(buf, PAGE_SIZE, "%d\n", temp->critical*1000);
return snprintf(buf, PAGE_SIZE, "%d\n",
therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_CRITICAL) * 1000);
}
static ssize_t
nouveau_hwmon_set_critical_temp(struct device *d, struct device_attribute *a,
......@@ -516,16 +456,14 @@ nouveau_hwmon_set_critical_temp(struct device *d, struct device_attribute *a,
size_t count)
{
struct drm_device *dev = dev_get_drvdata(d);
struct nouveau_pm *pm = nouveau_pm(dev);
struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp;
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_therm *therm = nouveau_therm(drm->device);
long value;
if (kstrtol(buf, 10, &value) == -EINVAL)
return count;
temp->critical = value/1000;
nouveau_temp_safety_checks(dev);
therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_CRITICAL, value / 1000);
return count;
}
......@@ -558,34 +496,9 @@ nouveau_hwmon_show_fan0_input(struct device *d, struct device_attribute *attr,
{
struct drm_device *dev = dev_get_drvdata(d);
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_timer *ptimer = nouveau_timer(drm->device);
struct nouveau_gpio *gpio = nouveau_gpio(drm->device);
struct dcb_gpio_func func;
u32 cycles, cur, prev;
u64 start;
if (gpio->find(gpio, 0, DCB_GPIO_FAN_SENSE, 0xff, &func))
return -ENODEV;
/* Monitor the GPIO input 0x3b for 250ms.
* When the fan spins, it changes the value of GPIO FAN_SENSE.
* We get 4 changes (0 -> 1 -> 0 -> 1 -> [...]) per complete rotation.
*/
start = ptimer->read(ptimer);
prev = gpio->get(gpio, 0, func.func, func.line);
cycles = 0;
do {
cur = gpio->get(gpio, 0, func.func, func.line);
if (prev != cur) {
cycles++;
prev = cur;
}
struct nouveau_therm *therm = nouveau_therm(drm->device);
usleep_range(500, 1000); /* supports 0 < rpm < 7500 */
} while (ptimer->read(ptimer) - start < 250000000);
/* interpolate to get rpm */
return sprintf(buf, "%i\n", cycles / 4 * 4 * 60);
return snprintf(buf, PAGE_SIZE, "%d\n", therm->fan_sense(therm));
}
static SENSOR_DEVICE_ATTR(fan0_input, S_IRUGO, nouveau_hwmon_show_fan0_input,
NULL, 0);
......@@ -594,9 +507,11 @@ static ssize_t
nouveau_hwmon_get_pwm0(struct device *d, struct device_attribute *a, char *buf)
{
struct drm_device *dev = dev_get_drvdata(d);
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_therm *therm = nouveau_therm(drm->device);
int ret;
ret = nouveau_pwmfan_get(dev);
ret = therm->fan_get(therm);
if (ret < 0)
return ret;
......@@ -608,7 +523,8 @@ nouveau_hwmon_set_pwm0(struct device *d, struct device_attribute *a,
const char *buf, size_t count)
{
struct drm_device *dev = dev_get_drvdata(d);
struct nouveau_pm *pm = nouveau_pm(dev);
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_therm *therm = nouveau_therm(drm->device);
int ret = -ENODEV;
long value;
......@@ -618,12 +534,7 @@ nouveau_hwmon_set_pwm0(struct device *d, struct device_attribute *a,
if (kstrtol(buf, 10, &value) == -EINVAL)
return -EINVAL;
if (value < pm->fan.min_duty)
value = pm->fan.min_duty;
if (value > pm->fan.max_duty)
value = pm->fan.max_duty;
ret = nouveau_pwmfan_set(dev, value);
ret = therm->fan_set(therm, value);
if (ret)
return ret;
......@@ -639,9 +550,15 @@ nouveau_hwmon_get_pwm0_min(struct device *d,
struct device_attribute *a, char *buf)
{
struct drm_device *dev = dev_get_drvdata(d);
struct nouveau_pm *pm = nouveau_pm(dev);
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_therm *therm = nouveau_therm(drm->device);
int ret;
ret = therm->attr_get(therm, NOUVEAU_THERM_ATTR_FAN_MIN_DUTY);
if (ret < 0)
return ret;
return sprintf(buf, "%i\n", pm->fan.min_duty);
return sprintf(buf, "%i\n", ret);
}
static ssize_t
......@@ -649,22 +566,17 @@ nouveau_hwmon_set_pwm0_min(struct device *d, struct device_attribute *a,
const char *buf, size_t count)
{
struct drm_device *dev = dev_get_drvdata(d);
struct nouveau_pm *pm = nouveau_pm(dev);
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_therm *therm = nouveau_therm(drm->device);
long value;
int ret;
if (kstrtol(buf, 10, &value) == -EINVAL)
return -EINVAL;
if (value < 0)
value = 0;
if (pm->fan.max_duty - value < 10)
value = pm->fan.max_duty - 10;
if (value < 10)
pm->fan.min_duty = 10;
else
pm->fan.min_duty = value;
ret = therm->attr_set(therm, NOUVEAU_THERM_ATTR_FAN_MIN_DUTY, value);
if (ret < 0)
return ret;
return count;
}
......@@ -678,9 +590,15 @@ nouveau_hwmon_get_pwm0_max(struct device *d,
struct device_attribute *a, char *buf)
{
struct drm_device *dev = dev_get_drvdata(d);
struct nouveau_pm *pm = nouveau_pm(dev);
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_therm *therm = nouveau_therm(drm->device);
int ret;
return sprintf(buf, "%i\n", pm->fan.max_duty);
ret = therm->attr_get(therm, NOUVEAU_THERM_ATTR_FAN_MAX_DUTY);
if (ret < 0)
return ret;
return sprintf(buf, "%i\n", ret);
}
static ssize_t
......@@ -688,22 +606,17 @@ nouveau_hwmon_set_pwm0_max(struct device *d, struct device_attribute *a,
const char *buf, size_t count)
{
struct drm_device *dev = dev_get_drvdata(d);
struct nouveau_pm *pm = nouveau_pm(dev);
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_therm *therm = nouveau_therm(drm->device);
long value;
int ret;
if (kstrtol(buf, 10, &value) == -EINVAL)
return -EINVAL;
if (value < 0)
value = 0;
if (value - pm->fan.min_duty < 10)
value = pm->fan.min_duty + 10;
if (value > 100)
pm->fan.max_duty = 100;
else
pm->fan.max_duty = value;
ret = therm->attr_set(therm, NOUVEAU_THERM_ATTR_FAN_MAX_DUTY, value);
if (ret < 0)
return ret;
return count;
}
......@@ -747,14 +660,14 @@ nouveau_hwmon_init(struct drm_device *dev)
{
struct nouveau_pm *pm = nouveau_pm(dev);
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_gpio *gpio = nouveau_gpio(drm->device);
struct dcb_gpio_func func;
struct nouveau_therm *therm = nouveau_therm(drm->device);
#if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE))
struct device *hwmon_dev;
int ret = 0;
if (!pm->temp_get)
if (!therm || !therm->temp_get || !therm->attr_get ||
!therm->attr_set || therm->temp_get(therm) < 0)
return -ENODEV;
hwmon_dev = hwmon_device_register(&dev->pdev->dev);
......@@ -776,7 +689,7 @@ nouveau_hwmon_init(struct drm_device *dev)
/*XXX: incorrect, need better detection for this, some boards have
* the gpio entries for pwm fan control even when there's no
* actual fan connected to it... therm table? */
if (nouveau_pwmfan_get(dev) >= 0) {
if (therm->fan_get && therm->fan_get(therm) >= 0) {
ret = sysfs_create_group(&dev->pdev->dev.kobj,
&hwmon_pwm_fan_attrgroup);
if (ret)
......@@ -784,7 +697,7 @@ nouveau_hwmon_init(struct drm_device *dev)
}
/* if the card can read the fan rpm */
if (!gpio->find(gpio, 0, DCB_GPIO_FAN_SENSE, 0xff, &func)) {
if (therm->fan_sense(therm) >= 0) {
ret = sysfs_create_group(&dev->pdev->dev.kobj,
&hwmon_fan_rpm_attrgroup);
if (ret)
......@@ -873,9 +786,6 @@ nouveau_pm_init(struct drm_device *dev)
pm->clocks_set = nv40_pm_clocks_set;
pm->voltage_get = nouveau_voltage_gpio_get;
pm->voltage_set = nouveau_voltage_gpio_set;
pm->temp_get = nv40_temp_get;
pm->pwm_get = nv40_pm_pwm_get;
pm->pwm_set = nv40_pm_pwm_set;
} else
if (device->card_type < NV_C0) {
if (device->chipset < 0xa3 ||
......@@ -891,9 +801,6 @@ nouveau_pm_init(struct drm_device *dev)
}
pm->voltage_get = nouveau_voltage_gpio_get;
pm->voltage_set = nouveau_voltage_gpio_set;
pm->temp_get = nv84_temp_get;
pm->pwm_get = nv50_pm_pwm_get;
pm->pwm_set = nv50_pm_pwm_set;
} else
if (device->card_type < NV_E0) {
pm->clocks_get = nvc0_pm_clocks_get;
......@@ -901,17 +808,11 @@ nouveau_pm_init(struct drm_device *dev)
pm->clocks_set = nvc0_pm_clocks_set;
pm->voltage_get = nouveau_voltage_gpio_get;
pm->voltage_set = nouveau_voltage_gpio_set;
pm->temp_get = nv84_temp_get;
if (device->card_type < NV_D0) {
pm->pwm_get = nv50_pm_pwm_get;
pm->pwm_set = nv50_pm_pwm_set;
}
}
/* parse aux tables from vbios */
nouveau_volt_init(dev);
nouveau_temp_init(dev);
INIT_LIST_HEAD(&pm->profiles);
......@@ -950,9 +851,6 @@ nouveau_pm_init(struct drm_device *dev)
if (nouveau_perflvl != NULL)
nouveau_pm_profile_set(dev, nouveau_perflvl);
/* determine the current fan speed */
pm->fan.percent = nouveau_pwmfan_get(dev);
nouveau_sysfs_init(dev);
nouveau_hwmon_init(dev);
#if defined(CONFIG_ACPI) && defined(CONFIG_POWER_SUPPLY)
......@@ -977,7 +875,6 @@ nouveau_pm_fini(struct drm_device *dev)
if (pm->cur != &pm->boot)
nouveau_pm_perflvl_set(dev, &pm->boot);
nouveau_temp_fini(dev);
nouveau_perf_fini(dev);
nouveau_volt_fini(dev);
......@@ -1003,5 +900,4 @@ nouveau_pm_resume(struct drm_device *dev)
perflvl = pm->cur;
pm->cur = &pm->boot;
nouveau_pm_perflvl_set(dev, perflvl);
nouveau_pwmfan_set(dev, pm->fan.percent);
}
......@@ -150,14 +150,6 @@ struct nouveau_pm_threshold_temp {
s16 down_clock;
};
struct nouveau_pm_fan {
u32 percent;
u32 min_duty;
u32 max_duty;
u32 pwm_freq;
u32 pwm_divisor;
};
struct nouveau_pm {
struct drm_device *dev;
......@@ -166,7 +158,6 @@ struct nouveau_pm {
int nr_perflvl;
struct nouveau_pm_temp_sensor_constants sensor_constants;
struct nouveau_pm_threshold_temp threshold_temp;
struct nouveau_pm_fan fan;
struct nouveau_pm_profile *profile_ac;
struct nouveau_pm_profile *profile_dc;
......@@ -185,9 +176,6 @@ struct nouveau_pm {
int (*voltage_get)(struct drm_device *);
int (*voltage_set)(struct drm_device *, int voltage);
int (*pwm_get)(struct drm_device *, int line, u32*, u32*);
int (*pwm_set)(struct drm_device *, int line, u32, u32);
int (*temp_get)(struct drm_device *);
};
static inline struct nouveau_pm *
......@@ -270,13 +258,6 @@ int nvc0_pm_clocks_get(struct drm_device *, struct nouveau_pm_level *);
void *nvc0_pm_clocks_pre(struct drm_device *, struct nouveau_pm_level *);
int nvc0_pm_clocks_set(struct drm_device *, void *);
/* nouveau_temp.c */
void nouveau_temp_init(struct drm_device *dev);
void nouveau_temp_fini(struct drm_device *dev);
void nouveau_temp_safety_checks(struct drm_device *dev);
int nv40_temp_get(struct drm_device *dev);
int nv84_temp_get(struct drm_device *dev);
/* nouveau_mem.c */
int nouveau_mem_timing_calc(struct drm_device *, u32 freq,
struct nouveau_pm_memtiming *);
......
......@@ -351,52 +351,3 @@ nv40_pm_clocks_set(struct drm_device *dev, void *pre_state)
kfree(info);
return ret;
}
int
nv40_pm_pwm_get(struct drm_device *dev, int line, u32 *divs, u32 *duty)
{
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_device *device = nouveau_dev(dev);
if (line == 2) {
u32 reg = nv_rd32(device, 0x0010f0);
if (reg & 0x80000000) {
*duty = (reg & 0x7fff0000) >> 16;
*divs = (reg & 0x00007fff);
return 0;
}
} else
if (line == 9) {
u32 reg = nv_rd32(device, 0x0015f4);
if (reg & 0x80000000) {
*divs = nv_rd32(device, 0x0015f8);
*duty = (reg & 0x7fffffff);
return 0;
}
} else {
NV_ERROR(drm, "unknown pwm ctrl for gpio %d\n", line);
return -ENODEV;
}
return -EINVAL;
}
int
nv40_pm_pwm_set(struct drm_device *dev, int line, u32 divs, u32 duty)
{
struct nouveau_device *device = nouveau_dev(dev);
struct nouveau_drm *drm = nouveau_drm(dev);
if (line == 2) {
nv_wr32(device, 0x0010f0, 0x80000000 | (duty << 16) | divs);
} else
if (line == 9) {
nv_wr32(device, 0x0015f8, divs);
nv_wr32(device, 0x0015f4, duty | 0x80000000);
} else {
NV_ERROR(drm, "unknown pwm ctrl for gpio %d\n", line);
return -ENODEV;
}
return 0;
}
......@@ -853,61 +853,3 @@ nv50_pm_clocks_set(struct drm_device *dev, void *data)
kfree(info);
return ret;
}
static int
pwm_info(struct drm_device *dev, int *line, int *ctrl, int *indx)
{
struct nouveau_drm *drm = nouveau_drm(dev);
if (*line == 0x04) {
*ctrl = 0x00e100;
*line = 4;
*indx = 0;
} else
if (*line == 0x09) {
*ctrl = 0x00e100;
*line = 9;
*indx = 1;
} else
if (*line == 0x10) {
*ctrl = 0x00e28c;
*line = 0;
*indx = 0;
} else {
NV_ERROR(drm, "unknown pwm ctrl for gpio %d\n", *line);
return -ENODEV;
}
return 0;
}
int
nv50_pm_pwm_get(struct drm_device *dev, int line, u32 *divs, u32 *duty)
{
struct nouveau_device *device = nouveau_dev(dev);
int ctrl, id, ret = pwm_info(dev, &line, &ctrl, &id);
if (ret)
return ret;
if (nv_rd32(device, ctrl) & (1 << line)) {
*divs = nv_rd32(device, 0x00e114 + (id * 8));
*duty = nv_rd32(device, 0x00e118 + (id * 8));
return 0;
}
return -EINVAL;
}
int
nv50_pm_pwm_set(struct drm_device *dev, int line, u32 divs, u32 duty)
{
struct nouveau_device *device = nouveau_dev(dev);
int ctrl, id, ret = pwm_info(dev, &line, &ctrl, &id);
if (ret)
return ret;
nv_mask(device, ctrl, 0x00010001 << line, 0x00000001 << line);
nv_wr32(device, 0x00e114 + (id * 8), divs);
nv_wr32(device, 0x00e118 + (id * 8), duty | 0x80000000);
return 0;
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册