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: Martin Peres <martin.peres@labri.fr> Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
This commit is contained in:
parent
d46497dce7
commit
aa1b9b4836
|
@ -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,
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
#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;
|
||||
|
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* 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);
|
||||
}
|
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* 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"),
|
||||
* 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 <subdev/i2c.h>
|
||||
#include <subdev/bios/extdev.h>
|
||||
|
||||
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);
|
||||
|
||||
client = i2c_new_device(&i2c->adapter, info);
|
||||
if (!client)
|
||||
return false;
|
||||
|
||||
if (!client->driver || client->driver->detect(client, info)) {
|
||||
i2c_unregister_device(client);
|
||||
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;
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_therm_ic_ctor(struct nouveau_therm *therm)
|
||||
{
|
||||
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) },
|
||||
{ I2C_BOARD_INFO("w83781d", 0x2d) },
|
||||
{ I2C_BOARD_INFO("adt7473", 0x2e) },
|
||||
{ I2C_BOARD_INFO("adt7473", 0x2d) },
|
||||
{ I2C_BOARD_INFO("adt7473", 0x2c) },
|
||||
{ I2C_BOARD_INFO("f75375", 0x2e) },
|
||||
{ I2C_BOARD_INFO("lm99", 0x4c) },
|
||||
{ I2C_BOARD_INFO("lm90", 0x4c) },
|
||||
{ I2C_BOARD_INFO("lm90", 0x4d) },
|
||||
{ I2C_BOARD_INFO("adm1021", 0x18) },
|
||||
{ I2C_BOARD_INFO("adm1021", 0x19) },
|
||||
{ I2C_BOARD_INFO("adm1021", 0x1a) },
|
||||
{ I2C_BOARD_INFO("adm1021", 0x29) },
|
||||
{ I2C_BOARD_INFO("adm1021", 0x2a) },
|
||||
{ I2C_BOARD_INFO("adm1021", 0x2b) },
|
||||
{ I2C_BOARD_INFO("adm1021", 0x4c) },
|
||||
{ I2C_BOARD_INFO("adm1021", 0x4d) },
|
||||
{ I2C_BOARD_INFO("adm1021", 0x4e) },
|
||||
{ I2C_BOARD_INFO("lm63", 0x18) },
|
||||
{ I2C_BOARD_INFO("lm63", 0x4e) },
|
||||
{ }
|
||||
};
|
||||
|
||||
if (!nvbios_extdev_find(bios, NVBIOS_EXTDEV_LM89, &extdev_entry)) {
|
||||
struct i2c_board_info board[] = {
|
||||
{ I2C_BOARD_INFO("lm90", extdev_entry.addr >> 1) },
|
||||
{ }
|
||||
};
|
||||
|
||||
i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device",
|
||||
board, probe_monitoring_device);
|
||||
if (priv->ic)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!nvbios_extdev_find(bios, NVBIOS_EXTDEV_ADT7473, &extdev_entry)) {
|
||||
struct i2c_board_info board[] = {
|
||||
{ I2C_BOARD_INFO("adt7473", extdev_entry.addr >> 1) },
|
||||
{ }
|
||||
};
|
||||
|
||||
i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device",
|
||||
board, probe_monitoring_device);
|
||||
if (priv->ic)
|
||||
return;
|
||||
}
|
||||
|
||||
/* The vbios doesn't provide the address of an exisiting monitoring
|
||||
device. Let's try our static list.
|
||||
*/
|
||||
i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device", info,
|
||||
probe_monitoring_device);
|
||||
}
|
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
* 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,
|
||||
},
|
||||
};
|
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* 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,
|
||||
},
|
||||
};
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* 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);
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* 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;
|
||||
struct nouveau_therm *therm = nouveau_therm(drm->device);
|
||||
|
||||
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 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;
|
||||
|
||||
return sprintf(buf, "%i\n", pm->fan.min_duty);
|
||||
ret = therm->attr_get(therm, NOUVEAU_THERM_ATTR_FAN_MIN_DUTY);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
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 *);
|
||||
|
|
|
@ -1,237 +0,0 @@
|
|||
/*
|
||||
* Copyright 2010 PathScale 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: Martin Peres
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "drmP.h"
|
||||
|
||||
#include "nouveau_drm.h"
|
||||
#include "nouveau_pm.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 i2c_client *client;
|
||||
|
||||
request_module("%s%s", I2C_MODULE_PREFIX, info->type);
|
||||
|
||||
client = i2c_new_device(&i2c->adapter, info);
|
||||
if (!client)
|
||||
return false;
|
||||
|
||||
if (!client->driver || client->driver->detect(client, info)) {
|
||||
i2c_unregister_device(client);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
nouveau_temp_probe_i2c(struct drm_device *dev)
|
||||
{
|
||||
struct nouveau_device *device = nouveau_dev(dev);
|
||||
struct nouveau_bios *bios = nouveau_bios(device);
|
||||
struct nouveau_i2c *i2c = nouveau_i2c(device);
|
||||
struct nvbios_extdev_func extdev_entry;
|
||||
struct i2c_board_info info[] = {
|
||||
{ I2C_BOARD_INFO("w83l785ts", 0x2d) },
|
||||
{ I2C_BOARD_INFO("w83781d", 0x2d) },
|
||||
{ I2C_BOARD_INFO("adt7473", 0x2e) },
|
||||
{ I2C_BOARD_INFO("adt7473", 0x2d) },
|
||||
{ I2C_BOARD_INFO("adt7473", 0x2c) },
|
||||
{ I2C_BOARD_INFO("f75375", 0x2e) },
|
||||
{ I2C_BOARD_INFO("lm99", 0x4c) },
|
||||
{ I2C_BOARD_INFO("lm90", 0x4c) },
|
||||
{ I2C_BOARD_INFO("lm90", 0x4d) },
|
||||
{ I2C_BOARD_INFO("adm1021", 0x18) },
|
||||
{ I2C_BOARD_INFO("adm1021", 0x19) },
|
||||
{ I2C_BOARD_INFO("adm1021", 0x1a) },
|
||||
{ I2C_BOARD_INFO("adm1021", 0x29) },
|
||||
{ I2C_BOARD_INFO("adm1021", 0x2a) },
|
||||
{ I2C_BOARD_INFO("adm1021", 0x2b) },
|
||||
{ I2C_BOARD_INFO("adm1021", 0x4c) },
|
||||
{ I2C_BOARD_INFO("adm1021", 0x4d) },
|
||||
{ I2C_BOARD_INFO("adm1021", 0x4e) },
|
||||
{ I2C_BOARD_INFO("lm63", 0x18) },
|
||||
{ I2C_BOARD_INFO("lm63", 0x4e) },
|
||||
{ }
|
||||
};
|
||||
|
||||
if (!nvbios_extdev_find(bios, NVBIOS_EXTDEV_LM89, &extdev_entry)) {
|
||||
struct i2c_board_info board[] = {
|
||||
{ I2C_BOARD_INFO("lm90", extdev_entry.addr >> 1) },
|
||||
{ }
|
||||
};
|
||||
|
||||
if (i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device",
|
||||
board, probe_monitoring_device))
|
||||
return;
|
||||
}
|
||||
|
||||
if (!nvbios_extdev_find(bios, NVBIOS_EXTDEV_ADT7473, &extdev_entry)) {
|
||||
struct i2c_board_info board[] = {
|
||||
{ I2C_BOARD_INFO("adt7473", extdev_entry.addr >> 1) },
|
||||
{ }
|
||||
};
|
||||
|
||||
if (i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device",
|
||||
board, probe_monitoring_device))
|
||||
return;
|
||||
}
|
||||
|
||||
/* The vbios doesn't provide the address of an exisiting monitoring
|
||||
device. Let's try our static list.
|
||||
*/
|
||||
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)
|
||||
{
|
||||
|
||||
}
|
|
@ -351,52 +351,3 @@ resume:
|
|||
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 @@ resume:
|
|||
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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue