Merge branch 'linux-4.9' of git://github.com/skeggsb/linux into drm-next
Karol's work which greatly improves volt/clock changes on a heap of boards, nothing too exciting beyond a random collection of fixes. * 'linux-4.9' of git://github.com/skeggsb/linux: (33 commits) drm/nouveau/fb/nv50: defer DMA mapping of scratch page to oneinit() hook drm/nouveau/fb/gf100: defer DMA mapping of scratch page to oneinit() hook drm/nouveau/pci: set streaming DMA mask early drm/nouveau/kms: add Maxwell to backlight initialization drm/nouveau/bar/nv50: fix bar2 vm size drm/nouveau/disp: remove unused function in sorg94.c drm/nouveau/volt: use kernel's 64-bit signed division function drm/nouveau/core: add missing header dependencies drm/nouveau/gr/nv3x: add 0x0597 kelvin 3d class support drm/nouveau/drm/nouveau: add a LED driver for the NVIDIA logo drm/nouveau/fb/ram: Use Kepler implementation on Maxwell drm/nouveau/volt: Make use of cvb coefficients drm/nouveau/volt/gf100-: Add speedo drm/nouveau/volt: Add implementation for gf100 drm/nouveau/bios/vmap: unk0 field is the mode drm/nouveau/volt: Don't require perfect fit drm/nouveau/clk: Allow boosting only when NvBoost is set drm/nouveau/bios: Add parsing of VPSTATE table drm/nouveau/clk: Respect voltage limits in nvkm_cstate_prog drm/nouveau/clk: Fixup cstate selection ...
This commit is contained in:
commit
fb422950c6
|
@ -22,6 +22,7 @@ nouveau-$(CONFIG_DEBUG_FS) += nouveau_debugfs.o
|
|||
nouveau-y += nouveau_drm.o
|
||||
nouveau-y += nouveau_hwmon.o
|
||||
nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o
|
||||
nouveau-$(CONFIG_LEDS_CLASS) += nouveau_led.o
|
||||
nouveau-y += nouveau_nvif.o
|
||||
nouveau-$(CONFIG_NOUVEAU_PLATFORM_DRIVER) += nouveau_platform.o
|
||||
nouveau-y += nouveau_usif.o # userspace <-> nvif
|
||||
|
|
|
@ -6,6 +6,7 @@ enum dcb_gpio_func_name {
|
|||
DCB_GPIO_TVDAC1 = 0x2d,
|
||||
DCB_GPIO_FAN = 0x09,
|
||||
DCB_GPIO_FAN_SENSE = 0x3d,
|
||||
DCB_GPIO_LOGO_LED_PWM = 0x84,
|
||||
DCB_GPIO_UNUSED = 0xff,
|
||||
DCB_GPIO_VID0 = 0x04,
|
||||
DCB_GPIO_VID1 = 0x05,
|
||||
|
|
|
@ -1,10 +1,16 @@
|
|||
#ifndef __NVBIOS_ICCSENSE_H__
|
||||
#define __NVBIOS_ICCSENSE_H__
|
||||
struct pwr_rail_resistor_t {
|
||||
u8 mohm;
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
struct pwr_rail_t {
|
||||
u8 mode;
|
||||
u8 extdev_id;
|
||||
u8 resistor_mohm;
|
||||
u8 rail;
|
||||
u8 resistor_count;
|
||||
struct pwr_rail_resistor_t resistors[3];
|
||||
u16 config;
|
||||
};
|
||||
|
||||
struct nvbios_iccsense {
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
#ifndef __NVBIOS_VMAP_H__
|
||||
#define __NVBIOS_VMAP_H__
|
||||
struct nvbios_vmap {
|
||||
u8 max0;
|
||||
u8 max1;
|
||||
u8 max2;
|
||||
};
|
||||
|
||||
u16 nvbios_vmap_table(struct nvkm_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
|
||||
|
@ -8,7 +11,7 @@ u16 nvbios_vmap_parse(struct nvkm_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
|
|||
struct nvbios_vmap *);
|
||||
|
||||
struct nvbios_vmap_entry {
|
||||
u8 unk0;
|
||||
u8 mode;
|
||||
u8 link;
|
||||
u32 min;
|
||||
u32 max;
|
||||
|
|
|
@ -13,8 +13,9 @@ struct nvbios_volt {
|
|||
u32 base;
|
||||
|
||||
/* GPIO mode */
|
||||
u8 vidmask;
|
||||
s16 step;
|
||||
bool ranged;
|
||||
u8 vidmask;
|
||||
s16 step;
|
||||
|
||||
/* PWM mode */
|
||||
u32 pwm_freq;
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
#ifndef __NVBIOS_VPSTATE_H__
|
||||
#define __NVBIOS_VPSTATE_H__
|
||||
struct nvbios_vpstate_header {
|
||||
u32 offset;
|
||||
|
||||
u8 version;
|
||||
u8 hlen;
|
||||
u8 ecount;
|
||||
u8 elen;
|
||||
u8 scount;
|
||||
u8 slen;
|
||||
|
||||
u8 base_id;
|
||||
u8 boost_id;
|
||||
u8 tdp_id;
|
||||
};
|
||||
struct nvbios_vpstate_entry {
|
||||
u8 pstate;
|
||||
u16 clock_mhz;
|
||||
};
|
||||
int nvbios_vpstate_parse(struct nvkm_bios *, struct nvbios_vpstate_header *);
|
||||
int nvbios_vpstate_entry(struct nvkm_bios *, struct nvbios_vpstate_header *,
|
||||
u8 idx, struct nvbios_vpstate_entry *);
|
||||
#endif
|
|
@ -6,6 +6,10 @@
|
|||
struct nvbios_pll;
|
||||
struct nvkm_pll_vals;
|
||||
|
||||
#define NVKM_CLK_CSTATE_DEFAULT -1 /* POSTed default */
|
||||
#define NVKM_CLK_CSTATE_BASE -2 /* pstate base */
|
||||
#define NVKM_CLK_CSTATE_HIGHEST -3 /* highest possible */
|
||||
|
||||
enum nv_clk_src {
|
||||
nv_clk_src_crystal,
|
||||
nv_clk_src_href,
|
||||
|
@ -52,6 +56,7 @@ struct nvkm_cstate {
|
|||
struct list_head head;
|
||||
u8 voltage;
|
||||
u32 domain[nv_clk_src_max];
|
||||
u8 id;
|
||||
};
|
||||
|
||||
struct nvkm_pstate {
|
||||
|
@ -67,7 +72,8 @@ struct nvkm_pstate {
|
|||
struct nvkm_domain {
|
||||
enum nv_clk_src name;
|
||||
u8 bios; /* 0xff for none */
|
||||
#define NVKM_CLK_DOM_FLAG_CORE 0x01
|
||||
#define NVKM_CLK_DOM_FLAG_CORE 0x01
|
||||
#define NVKM_CLK_DOM_FLAG_VPSTATE 0x02
|
||||
u8 flags;
|
||||
const char *mname;
|
||||
int mdiv;
|
||||
|
@ -93,10 +99,16 @@ struct nvkm_clk {
|
|||
int ustate_ac; /* user-requested (-1 disabled, -2 perfmon) */
|
||||
int ustate_dc; /* user-requested (-1 disabled, -2 perfmon) */
|
||||
int astate; /* perfmon adjustment (base) */
|
||||
int tstate; /* thermal adjustment (max-) */
|
||||
int dstate; /* display adjustment (min+) */
|
||||
u8 temp;
|
||||
|
||||
bool allow_reclock;
|
||||
#define NVKM_CLK_BOOST_NONE 0x0
|
||||
#define NVKM_CLK_BOOST_BIOS 0x1
|
||||
#define NVKM_CLK_BOOST_FULL 0x2
|
||||
u8 boost_mode;
|
||||
u32 base_khz;
|
||||
u32 boost_khz;
|
||||
|
||||
/*XXX: die, these are here *only* to support the completely
|
||||
* bat-shit insane what-was-nouveau_hw.c code
|
||||
|
@ -110,7 +122,7 @@ int nvkm_clk_read(struct nvkm_clk *, enum nv_clk_src);
|
|||
int nvkm_clk_ustate(struct nvkm_clk *, int req, int pwr);
|
||||
int nvkm_clk_astate(struct nvkm_clk *, int req, int rel, bool wait);
|
||||
int nvkm_clk_dstate(struct nvkm_clk *, int req, int rel);
|
||||
int nvkm_clk_tstate(struct nvkm_clk *, int req, int rel);
|
||||
int nvkm_clk_tstate(struct nvkm_clk *, u8 temperature);
|
||||
|
||||
int nv04_clk_new(struct nvkm_device *, int, struct nvkm_clk **);
|
||||
int nv40_clk_new(struct nvkm_device *, int, struct nvkm_clk **);
|
||||
|
|
|
@ -15,12 +15,28 @@ struct nvkm_volt {
|
|||
|
||||
u32 max_uv;
|
||||
u32 min_uv;
|
||||
|
||||
/*
|
||||
* These are fully functional map entries creating a sw ceiling for
|
||||
* the voltage. These all can describe different kind of curves, so
|
||||
* that for any given temperature a different one can return the lowest
|
||||
* value of all three.
|
||||
*/
|
||||
u8 max0_id;
|
||||
u8 max1_id;
|
||||
u8 max2_id;
|
||||
|
||||
int speedo;
|
||||
};
|
||||
|
||||
int nvkm_volt_map(struct nvkm_volt *volt, u8 id, u8 temperature);
|
||||
int nvkm_volt_map_min(struct nvkm_volt *volt, u8 id);
|
||||
int nvkm_volt_get(struct nvkm_volt *);
|
||||
int nvkm_volt_set_id(struct nvkm_volt *, u8 id, int condition);
|
||||
int nvkm_volt_set_id(struct nvkm_volt *, u8 id, u8 min_id, u8 temp,
|
||||
int condition);
|
||||
|
||||
int nv40_volt_new(struct nvkm_device *, int, struct nvkm_volt **);
|
||||
int gf100_volt_new(struct nvkm_device *, int, struct nvkm_volt **);
|
||||
int gk104_volt_new(struct nvkm_device *, int, struct nvkm_volt **);
|
||||
int gk20a_volt_new(struct nvkm_device *, int, struct nvkm_volt **);
|
||||
int gm20b_volt_new(struct nvkm_device *, int, struct nvkm_volt **);
|
||||
|
|
|
@ -232,6 +232,7 @@ nouveau_backlight_init(struct drm_device *dev)
|
|||
case NV_DEVICE_INFO_V0_TESLA:
|
||||
case NV_DEVICE_INFO_V0_FERMI:
|
||||
case NV_DEVICE_INFO_V0_KEPLER:
|
||||
case NV_DEVICE_INFO_V0_MAXWELL:
|
||||
return nv50_backlight_init(connector);
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -31,10 +31,8 @@
|
|||
|
||||
#define DCB_LOC_ON_CHIP 0
|
||||
|
||||
#define ROM16(x) le16_to_cpu(*(u16 *)&(x))
|
||||
#define ROM32(x) le32_to_cpu(*(u32 *)&(x))
|
||||
#define ROM48(x) ({ u8 *p = &(x); (u64)ROM16(p[4]) << 32 | ROM32(p[0]); })
|
||||
#define ROM64(x) le64_to_cpu(*(u64 *)&(x))
|
||||
#define ROM16(x) get_unaligned_le16(&(x))
|
||||
#define ROM32(x) get_unaligned_le32(&(x))
|
||||
#define ROMPTR(d,x) ({ \
|
||||
struct nouveau_drm *drm = nouveau_drm((d)); \
|
||||
ROM16(x) ? &drm->vbios.data[ROM16(x)] : NULL; \
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#include "nouveau_ttm.h"
|
||||
#include "nouveau_gem.h"
|
||||
#include "nouveau_vga.h"
|
||||
#include "nouveau_led.h"
|
||||
#include "nouveau_hwmon.h"
|
||||
#include "nouveau_acpi.h"
|
||||
#include "nouveau_bios.h"
|
||||
|
@ -475,6 +476,7 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags)
|
|||
nouveau_hwmon_init(dev);
|
||||
nouveau_accel_init(drm);
|
||||
nouveau_fbcon_init(dev);
|
||||
nouveau_led_init(dev);
|
||||
|
||||
if (nouveau_runtime_pm != 0) {
|
||||
pm_runtime_use_autosuspend(dev->dev);
|
||||
|
@ -510,6 +512,7 @@ nouveau_drm_unload(struct drm_device *dev)
|
|||
pm_runtime_forbid(dev->dev);
|
||||
}
|
||||
|
||||
nouveau_led_fini(dev);
|
||||
nouveau_fbcon_fini(dev);
|
||||
nouveau_accel_fini(drm);
|
||||
nouveau_hwmon_fini(dev);
|
||||
|
@ -561,6 +564,8 @@ nouveau_do_suspend(struct drm_device *dev, bool runtime)
|
|||
struct nouveau_cli *cli;
|
||||
int ret;
|
||||
|
||||
nouveau_led_suspend(dev);
|
||||
|
||||
if (dev->mode_config.num_crtc) {
|
||||
NV_INFO(drm, "suspending console...\n");
|
||||
nouveau_fbcon_set_suspend(dev, 1);
|
||||
|
@ -649,6 +654,8 @@ nouveau_do_resume(struct drm_device *dev, bool runtime)
|
|||
nouveau_fbcon_set_suspend(dev, 0);
|
||||
}
|
||||
|
||||
nouveau_led_resume(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -166,6 +166,9 @@ struct nouveau_drm {
|
|||
struct nouveau_hwmon *hwmon;
|
||||
struct nouveau_debugfs *debugfs;
|
||||
|
||||
/* led management */
|
||||
struct nouveau_led *led;
|
||||
|
||||
/* display power reference */
|
||||
bool have_disp_power_ref;
|
||||
|
||||
|
|
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
* Copyright (C) 2016 Martin Peres
|
||||
*
|
||||
* 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 (including the
|
||||
* next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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 <martin.peres@free.fr>
|
||||
*/
|
||||
|
||||
#include <linux/leds.h>
|
||||
|
||||
#include "nouveau_led.h"
|
||||
#include <nvkm/subdev/gpio.h>
|
||||
|
||||
static enum led_brightness
|
||||
nouveau_led_get_brightness(struct led_classdev *led)
|
||||
{
|
||||
struct drm_device *drm_dev = container_of(led, struct nouveau_led, led)->dev;
|
||||
struct nouveau_drm *drm = nouveau_drm(drm_dev);
|
||||
struct nvif_object *device = &drm->device.object;
|
||||
u32 div, duty;
|
||||
|
||||
div = nvif_rd32(device, 0x61c880) & 0x00ffffff;
|
||||
duty = nvif_rd32(device, 0x61c884) & 0x00ffffff;
|
||||
|
||||
if (div > 0)
|
||||
return duty * LED_FULL / div;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
nouveau_led_set_brightness(struct led_classdev *led, enum led_brightness value)
|
||||
{
|
||||
struct drm_device *drm_dev = container_of(led, struct nouveau_led, led)->dev;
|
||||
struct nouveau_drm *drm = nouveau_drm(drm_dev);
|
||||
struct nvif_object *device = &drm->device.object;
|
||||
|
||||
u32 input_clk = 27e6; /* PDISPLAY.SOR[1].PWM is connected to the crystal */
|
||||
u32 freq = 100; /* this is what nvidia uses and it should be good-enough */
|
||||
u32 div, duty;
|
||||
|
||||
div = input_clk / freq;
|
||||
duty = value * div / LED_FULL;
|
||||
|
||||
/* for now, this is safe to directly poke those registers because:
|
||||
* - A: nvidia never puts the logo led to any other PWM controler
|
||||
* than PDISPLAY.SOR[1].PWM.
|
||||
* - B: nouveau does not touch these registers anywhere else
|
||||
*/
|
||||
nvif_wr32(device, 0x61c880, div);
|
||||
nvif_wr32(device, 0x61c884, 0xc0000000 | duty);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
nouveau_led_init(struct drm_device *dev)
|
||||
{
|
||||
struct nouveau_drm *drm = nouveau_drm(dev);
|
||||
struct nvkm_gpio *gpio = nvxx_gpio(&drm->device);
|
||||
struct dcb_gpio_func logo_led;
|
||||
int ret;
|
||||
|
||||
if (!gpio)
|
||||
return 0;
|
||||
|
||||
/* check that there is a GPIO controlling the logo LED */
|
||||
if (nvkm_gpio_find(gpio, 0, DCB_GPIO_LOGO_LED_PWM, 0xff, &logo_led))
|
||||
return 0;
|
||||
|
||||
drm->led = kzalloc(sizeof(*drm->led), GFP_KERNEL);
|
||||
if (!drm->led)
|
||||
return -ENOMEM;
|
||||
drm->led->dev = dev;
|
||||
|
||||
drm->led->led.name = "nvidia-logo";
|
||||
drm->led->led.max_brightness = 255;
|
||||
drm->led->led.brightness_get = nouveau_led_get_brightness;
|
||||
drm->led->led.brightness_set = nouveau_led_set_brightness;
|
||||
|
||||
ret = led_classdev_register(dev->dev, &drm->led->led);
|
||||
if (ret) {
|
||||
kfree(drm->led);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_led_suspend(struct drm_device *dev)
|
||||
{
|
||||
struct nouveau_drm *drm = nouveau_drm(dev);
|
||||
|
||||
if (drm->led)
|
||||
led_classdev_suspend(&drm->led->led);
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_led_resume(struct drm_device *dev)
|
||||
{
|
||||
struct nouveau_drm *drm = nouveau_drm(dev);
|
||||
|
||||
if (drm->led)
|
||||
led_classdev_resume(&drm->led->led);
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_led_fini(struct drm_device *dev)
|
||||
{
|
||||
struct nouveau_drm *drm = nouveau_drm(dev);
|
||||
|
||||
if (drm->led) {
|
||||
led_classdev_unregister(&drm->led->led);
|
||||
kfree(drm->led);
|
||||
drm->led = NULL;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright 2015 Martin Peres
|
||||
*
|
||||
* 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 <martin.peres@free.fr>
|
||||
*/
|
||||
|
||||
#ifndef __NOUVEAU_LED_H__
|
||||
#define __NOUVEAU_LED_H__
|
||||
|
||||
#include "nouveau_drv.h"
|
||||
|
||||
struct led_classdev;
|
||||
|
||||
struct nouveau_led {
|
||||
struct drm_device *dev;
|
||||
|
||||
struct led_classdev led;
|
||||
};
|
||||
|
||||
static inline struct nouveau_led *
|
||||
nouveau_led(struct drm_device *dev)
|
||||
{
|
||||
return nouveau_drm(dev)->led;
|
||||
}
|
||||
|
||||
/* nouveau_led.c */
|
||||
#if IS_ENABLED(CONFIG_LEDS_CLASS)
|
||||
int nouveau_led_init(struct drm_device *dev);
|
||||
void nouveau_led_suspend(struct drm_device *dev);
|
||||
void nouveau_led_resume(struct drm_device *dev);
|
||||
void nouveau_led_fini(struct drm_device *dev);
|
||||
#else
|
||||
static inline int nouveau_led_init(struct drm_device *dev) { return 0; };
|
||||
static inline void nouveau_led_suspend(struct drm_device *dev) { };
|
||||
static inline void nouveau_led_resume(struct drm_device *dev) { };
|
||||
static inline void nouveau_led_fini(struct drm_device *dev) { };
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -20,6 +20,7 @@
|
|||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include <core/device.h>
|
||||
#include <core/firmware.h>
|
||||
|
||||
/**
|
||||
* nvkm_firmware_get - load firmware from the official nvidia/chip/ directory
|
||||
|
|
|
@ -1357,7 +1357,7 @@ nvc0_chipset = {
|
|||
.pmu = gf100_pmu_new,
|
||||
.therm = gt215_therm_new,
|
||||
.timer = nv41_timer_new,
|
||||
.volt = nv40_volt_new,
|
||||
.volt = gf100_volt_new,
|
||||
.ce[0] = gf100_ce_new,
|
||||
.ce[1] = gf100_ce_new,
|
||||
.disp = gt215_disp_new,
|
||||
|
@ -1394,7 +1394,7 @@ nvc1_chipset = {
|
|||
.pmu = gf100_pmu_new,
|
||||
.therm = gt215_therm_new,
|
||||
.timer = nv41_timer_new,
|
||||
.volt = nv40_volt_new,
|
||||
.volt = gf100_volt_new,
|
||||
.ce[0] = gf100_ce_new,
|
||||
.disp = gt215_disp_new,
|
||||
.dma = gf100_dma_new,
|
||||
|
@ -1430,7 +1430,7 @@ nvc3_chipset = {
|
|||
.pmu = gf100_pmu_new,
|
||||
.therm = gt215_therm_new,
|
||||
.timer = nv41_timer_new,
|
||||
.volt = nv40_volt_new,
|
||||
.volt = gf100_volt_new,
|
||||
.ce[0] = gf100_ce_new,
|
||||
.disp = gt215_disp_new,
|
||||
.dma = gf100_dma_new,
|
||||
|
@ -1466,7 +1466,7 @@ nvc4_chipset = {
|
|||
.pmu = gf100_pmu_new,
|
||||
.therm = gt215_therm_new,
|
||||
.timer = nv41_timer_new,
|
||||
.volt = nv40_volt_new,
|
||||
.volt = gf100_volt_new,
|
||||
.ce[0] = gf100_ce_new,
|
||||
.ce[1] = gf100_ce_new,
|
||||
.disp = gt215_disp_new,
|
||||
|
@ -1503,7 +1503,7 @@ nvc8_chipset = {
|
|||
.pmu = gf100_pmu_new,
|
||||
.therm = gt215_therm_new,
|
||||
.timer = nv41_timer_new,
|
||||
.volt = nv40_volt_new,
|
||||
.volt = gf100_volt_new,
|
||||
.ce[0] = gf100_ce_new,
|
||||
.ce[1] = gf100_ce_new,
|
||||
.disp = gt215_disp_new,
|
||||
|
@ -1540,7 +1540,7 @@ nvce_chipset = {
|
|||
.pmu = gf100_pmu_new,
|
||||
.therm = gt215_therm_new,
|
||||
.timer = nv41_timer_new,
|
||||
.volt = nv40_volt_new,
|
||||
.volt = gf100_volt_new,
|
||||
.ce[0] = gf100_ce_new,
|
||||
.ce[1] = gf100_ce_new,
|
||||
.disp = gt215_disp_new,
|
||||
|
@ -1577,7 +1577,7 @@ nvcf_chipset = {
|
|||
.pmu = gf100_pmu_new,
|
||||
.therm = gt215_therm_new,
|
||||
.timer = nv41_timer_new,
|
||||
.volt = nv40_volt_new,
|
||||
.volt = gf100_volt_new,
|
||||
.ce[0] = gf100_ce_new,
|
||||
.disp = gt215_disp_new,
|
||||
.dma = gf100_dma_new,
|
||||
|
@ -1612,6 +1612,7 @@ nvd7_chipset = {
|
|||
.pci = gf106_pci_new,
|
||||
.therm = gf119_therm_new,
|
||||
.timer = nv41_timer_new,
|
||||
.volt = gf100_volt_new,
|
||||
.ce[0] = gf100_ce_new,
|
||||
.disp = gf119_disp_new,
|
||||
.dma = gf119_dma_new,
|
||||
|
@ -1647,7 +1648,7 @@ nvd9_chipset = {
|
|||
.pmu = gf119_pmu_new,
|
||||
.therm = gf119_therm_new,
|
||||
.timer = nv41_timer_new,
|
||||
.volt = nv40_volt_new,
|
||||
.volt = gf100_volt_new,
|
||||
.ce[0] = gf100_ce_new,
|
||||
.disp = gf119_disp_new,
|
||||
.dma = gf119_dma_new,
|
||||
|
|
|
@ -1665,14 +1665,31 @@ nvkm_device_pci_new(struct pci_dev *pci_dev, const char *cfg, const char *dbg,
|
|||
*pdevice = &pdev->device;
|
||||
pdev->pdev = pci_dev;
|
||||
|
||||
return nvkm_device_ctor(&nvkm_device_pci_func, quirk, &pci_dev->dev,
|
||||
pci_is_pcie(pci_dev) ? NVKM_DEVICE_PCIE :
|
||||
pci_find_capability(pci_dev, PCI_CAP_ID_AGP) ?
|
||||
NVKM_DEVICE_AGP : NVKM_DEVICE_PCI,
|
||||
(u64)pci_domain_nr(pci_dev->bus) << 32 |
|
||||
pci_dev->bus->number << 16 |
|
||||
PCI_SLOT(pci_dev->devfn) << 8 |
|
||||
PCI_FUNC(pci_dev->devfn), name,
|
||||
cfg, dbg, detect, mmio, subdev_mask,
|
||||
&pdev->device);
|
||||
ret = nvkm_device_ctor(&nvkm_device_pci_func, quirk, &pci_dev->dev,
|
||||
pci_is_pcie(pci_dev) ? NVKM_DEVICE_PCIE :
|
||||
pci_find_capability(pci_dev, PCI_CAP_ID_AGP) ?
|
||||
NVKM_DEVICE_AGP : NVKM_DEVICE_PCI,
|
||||
(u64)pci_domain_nr(pci_dev->bus) << 32 |
|
||||
pci_dev->bus->number << 16 |
|
||||
PCI_SLOT(pci_dev->devfn) << 8 |
|
||||
PCI_FUNC(pci_dev->devfn), name,
|
||||
cfg, dbg, detect, mmio, subdev_mask,
|
||||
&pdev->device);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Set a preliminary DMA mask based on the .dma_bits member of the
|
||||
* MMU subdevice. This allows other subdevices to create DMA mappings
|
||||
* in their init() or oneinit() methods, which may be called before the
|
||||
* TTM layer sets the DMA mask definitively.
|
||||
* This is necessary for platforms where the default DMA mask of 32
|
||||
* does not cover any system memory, i.e., when all RAM is > 4 GB.
|
||||
*/
|
||||
if (subdev_mask & BIT(NVKM_SUBDEV_MMU))
|
||||
dma_set_mask_and_coherent(&pci_dev->dev,
|
||||
DMA_BIT_MASK(pdev->device.mmu->dma_bits));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -45,14 +45,6 @@ static const struct nvkm_output_func
|
|||
g94_sor_output_func = {
|
||||
};
|
||||
|
||||
int
|
||||
g94_sor_output_new(struct nvkm_disp *disp, int index,
|
||||
struct dcb_output *dcbE, struct nvkm_output **poutp)
|
||||
{
|
||||
return nvkm_output_new_(&g94_sor_output_func, disp,
|
||||
index, dcbE, poutp);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* DisplayPort
|
||||
******************************************************************************/
|
||||
|
|
|
@ -187,6 +187,7 @@ nv30_gr = {
|
|||
{ -1, -1, 0x038a, &nv04_gr_object }, /* ifc (nv30) */
|
||||
{ -1, -1, 0x039e, &nv04_gr_object }, /* swzsurf (nv30) */
|
||||
{ -1, -1, 0x0397, &nv04_gr_object }, /* rankine */
|
||||
{ -1, -1, 0x0597, &nv04_gr_object }, /* kelvin */
|
||||
{}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -123,6 +123,7 @@ nv34_gr = {
|
|||
{ -1, -1, 0x0389, &nv04_gr_object }, /* sifm (nv30) */
|
||||
{ -1, -1, 0x038a, &nv04_gr_object }, /* ifc (nv30) */
|
||||
{ -1, -1, 0x039e, &nv04_gr_object }, /* swzsurf (nv30) */
|
||||
{ -1, -1, 0x0597, &nv04_gr_object }, /* kelvin */
|
||||
{ -1, -1, 0x0697, &nv04_gr_object }, /* rankine */
|
||||
{}
|
||||
}
|
||||
|
|
|
@ -124,6 +124,7 @@ nv35_gr = {
|
|||
{ -1, -1, 0x038a, &nv04_gr_object }, /* ifc (nv30) */
|
||||
{ -1, -1, 0x039e, &nv04_gr_object }, /* swzsurf (nv30) */
|
||||
{ -1, -1, 0x0497, &nv04_gr_object }, /* rankine */
|
||||
{ -1, -1, 0x0597, &nv04_gr_object }, /* kelvin */
|
||||
{}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -84,7 +84,7 @@ nv50_bar_oneinit(struct nvkm_bar *base)
|
|||
start = 0x0100000000ULL;
|
||||
limit = start + device->func->resource_size(device, 3);
|
||||
|
||||
ret = nvkm_vm_new(device, start, limit, start, &bar3_lock, &vm);
|
||||
ret = nvkm_vm_new(device, start, limit - start, start, &bar3_lock, &vm);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -117,7 +117,7 @@ nv50_bar_oneinit(struct nvkm_bar *base)
|
|||
start = 0x0000000000ULL;
|
||||
limit = start + device->func->resource_size(device, 1);
|
||||
|
||||
ret = nvkm_vm_new(device, start, limit--, start, &bar1_lock, &vm);
|
||||
ret = nvkm_vm_new(device, start, limit-- - start, start, &bar1_lock, &vm);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ nvkm-y += nvkm/subdev/bios/timing.o
|
|||
nvkm-y += nvkm/subdev/bios/therm.o
|
||||
nvkm-y += nvkm/subdev/bios/vmap.o
|
||||
nvkm-y += nvkm/subdev/bios/volt.o
|
||||
nvkm-y += nvkm/subdev/bios/vpstate.o
|
||||
nvkm-y += nvkm/subdev/bios/xpio.o
|
||||
nvkm-y += nvkm/subdev/bios/M0203.o
|
||||
nvkm-y += nvkm/subdev/bios/M0205.o
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
*/
|
||||
#include <subdev/bios.h>
|
||||
#include <subdev/bios/bit.h>
|
||||
#include <subdev/bios/extdev.h>
|
||||
#include <subdev/bios/iccsense.h>
|
||||
|
||||
static u16
|
||||
|
@ -77,23 +78,47 @@ nvbios_iccsense_parse(struct nvkm_bios *bios, struct nvbios_iccsense *iccsense)
|
|||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < cnt; ++i) {
|
||||
struct nvbios_extdev_func extdev;
|
||||
struct pwr_rail_t *rail = &iccsense->rail[i];
|
||||
u8 res_start = 0;
|
||||
int r;
|
||||
|
||||
entry = table + hdr + i * len;
|
||||
|
||||
switch(ver) {
|
||||
case 0x10:
|
||||
rail->mode = nvbios_rd08(bios, entry + 0x1);
|
||||
rail->extdev_id = nvbios_rd08(bios, entry + 0x2);
|
||||
rail->resistor_mohm = nvbios_rd08(bios, entry + 0x3);
|
||||
rail->rail = nvbios_rd08(bios, entry + 0x4);
|
||||
res_start = 0x3;
|
||||
break;
|
||||
case 0x20:
|
||||
rail->mode = nvbios_rd08(bios, entry);
|
||||
rail->extdev_id = nvbios_rd08(bios, entry + 0x1);
|
||||
rail->resistor_mohm = nvbios_rd08(bios, entry + 0x5);
|
||||
rail->rail = nvbios_rd08(bios, entry + 0x6);
|
||||
res_start = 0x5;
|
||||
break;
|
||||
};
|
||||
|
||||
if (nvbios_extdev_parse(bios, rail->extdev_id, &extdev))
|
||||
continue;
|
||||
|
||||
switch (extdev.type) {
|
||||
case NVBIOS_EXTDEV_INA209:
|
||||
case NVBIOS_EXTDEV_INA219:
|
||||
rail->resistor_count = 1;
|
||||
break;
|
||||
case NVBIOS_EXTDEV_INA3221:
|
||||
rail->resistor_count = 3;
|
||||
break;
|
||||
default:
|
||||
rail->resistor_count = 0;
|
||||
break;
|
||||
};
|
||||
|
||||
for (r = 0; r < rail->resistor_count; ++r) {
|
||||
rail->resistors[r].mohm = nvbios_rd08(bios, entry + res_start + r * 2);
|
||||
rail->resistors[r].enabled = !(nvbios_rd08(bios, entry + res_start + r * 2 + 1) & 0x40);
|
||||
}
|
||||
rail->config = nvbios_rd16(bios, entry + res_start + rail->resistor_count * 2);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -61,7 +61,17 @@ nvbios_vmap_parse(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
|
|||
memset(info, 0x00, sizeof(*info));
|
||||
switch (!!vmap * *ver) {
|
||||
case 0x10:
|
||||
info->max0 = 0xff;
|
||||
info->max1 = 0xff;
|
||||
info->max2 = 0xff;
|
||||
break;
|
||||
case 0x20:
|
||||
info->max0 = nvbios_rd08(bios, vmap + 0x7);
|
||||
info->max1 = nvbios_rd08(bios, vmap + 0x8);
|
||||
if (*len >= 0xc)
|
||||
info->max2 = nvbios_rd08(bios, vmap + 0xc);
|
||||
else
|
||||
info->max2 = 0xff;
|
||||
break;
|
||||
}
|
||||
return vmap;
|
||||
|
@ -95,7 +105,7 @@ nvbios_vmap_entry_parse(struct nvkm_bios *bios, int idx, u8 *ver, u8 *len,
|
|||
info->arg[2] = nvbios_rd32(bios, vmap + 0x10);
|
||||
break;
|
||||
case 0x20:
|
||||
info->unk0 = nvbios_rd08(bios, vmap + 0x00);
|
||||
info->mode = nvbios_rd08(bios, vmap + 0x00);
|
||||
info->link = nvbios_rd08(bios, vmap + 0x01);
|
||||
info->min = nvbios_rd32(bios, vmap + 0x02);
|
||||
info->max = nvbios_rd32(bios, vmap + 0x06);
|
||||
|
|
|
@ -75,20 +75,24 @@ nvbios_volt_parse(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
|
|||
case 0x12:
|
||||
info->type = NVBIOS_VOLT_GPIO;
|
||||
info->vidmask = nvbios_rd08(bios, volt + 0x04);
|
||||
info->ranged = false;
|
||||
break;
|
||||
case 0x20:
|
||||
info->type = NVBIOS_VOLT_GPIO;
|
||||
info->vidmask = nvbios_rd08(bios, volt + 0x05);
|
||||
info->ranged = false;
|
||||
break;
|
||||
case 0x30:
|
||||
info->type = NVBIOS_VOLT_GPIO;
|
||||
info->vidmask = nvbios_rd08(bios, volt + 0x04);
|
||||
info->ranged = false;
|
||||
break;
|
||||
case 0x40:
|
||||
info->type = NVBIOS_VOLT_GPIO;
|
||||
info->base = nvbios_rd32(bios, volt + 0x04);
|
||||
info->step = nvbios_rd16(bios, volt + 0x08);
|
||||
info->vidmask = nvbios_rd08(bios, volt + 0x0b);
|
||||
info->ranged = true; /* XXX: find the flag byte */
|
||||
/*XXX*/
|
||||
info->min = 0;
|
||||
info->max = info->base;
|
||||
|
@ -104,9 +108,11 @@ nvbios_volt_parse(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
|
|||
info->pwm_freq = nvbios_rd32(bios, volt + 0x5) / 1000;
|
||||
info->pwm_range = nvbios_rd32(bios, volt + 0x16);
|
||||
} else {
|
||||
info->type = NVBIOS_VOLT_GPIO;
|
||||
info->vidmask = nvbios_rd08(bios, volt + 0x06);
|
||||
info->step = nvbios_rd16(bios, volt + 0x16);
|
||||
info->type = NVBIOS_VOLT_GPIO;
|
||||
info->vidmask = nvbios_rd08(bios, volt + 0x06);
|
||||
info->step = nvbios_rd16(bios, volt + 0x16);
|
||||
info->ranged =
|
||||
!!(nvbios_rd08(bios, volt + 0x4) & 0x2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -142,7 +148,10 @@ nvbios_volt_entry_parse(struct nvkm_bios *bios, int idx, u8 *ver, u8 *len,
|
|||
info->vid = nvbios_rd08(bios, volt + 0x01) >> 2;
|
||||
break;
|
||||
case 0x40:
|
||||
break;
|
||||
case 0x50:
|
||||
info->voltage = nvbios_rd32(bios, volt) & 0x001fffff;
|
||||
info->vid = (nvbios_rd32(bios, volt) >> 23) & 0xff;
|
||||
break;
|
||||
}
|
||||
return volt;
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright 2016 Karol Herbst
|
||||
*
|
||||
* 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: Karol Herbst
|
||||
*/
|
||||
#include <subdev/bios.h>
|
||||
#include <subdev/bios/bit.h>
|
||||
#include <subdev/bios/vpstate.h>
|
||||
|
||||
static u32
|
||||
nvbios_vpstate_offset(struct nvkm_bios *b)
|
||||
{
|
||||
struct bit_entry bit_P;
|
||||
|
||||
if (!bit_entry(b, 'P', &bit_P)) {
|
||||
if (bit_P.version == 2)
|
||||
return nvbios_rd32(b, bit_P.offset + 0x38);
|
||||
}
|
||||
|
||||
return 0x0000;
|
||||
}
|
||||
|
||||
int
|
||||
nvbios_vpstate_parse(struct nvkm_bios *b, struct nvbios_vpstate_header *h)
|
||||
{
|
||||
if (!h)
|
||||
return -EINVAL;
|
||||
|
||||
h->offset = nvbios_vpstate_offset(b);
|
||||
if (!h->offset)
|
||||
return -ENODEV;
|
||||
|
||||
h->version = nvbios_rd08(b, h->offset);
|
||||
switch (h->version) {
|
||||
case 0x10:
|
||||
h->hlen = nvbios_rd08(b, h->offset + 0x1);
|
||||
h->elen = nvbios_rd08(b, h->offset + 0x2);
|
||||
h->slen = nvbios_rd08(b, h->offset + 0x3);
|
||||
h->scount = nvbios_rd08(b, h->offset + 0x4);
|
||||
h->ecount = nvbios_rd08(b, h->offset + 0x5);
|
||||
|
||||
h->base_id = nvbios_rd08(b, h->offset + 0x0f);
|
||||
h->boost_id = nvbios_rd08(b, h->offset + 0x10);
|
||||
h->tdp_id = nvbios_rd08(b, h->offset + 0x11);
|
||||
return 0;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
nvbios_vpstate_entry(struct nvkm_bios *b, struct nvbios_vpstate_header *h,
|
||||
u8 idx, struct nvbios_vpstate_entry *e)
|
||||
{
|
||||
u32 offset;
|
||||
|
||||
if (!e || !h || idx > h->ecount)
|
||||
return -EINVAL;
|
||||
|
||||
offset = h->offset + h->hlen + idx * (h->elen + (h->slen * h->scount));
|
||||
e->pstate = nvbios_rd08(b, offset);
|
||||
e->clock_mhz = nvbios_rd16(b, offset + 0x5);
|
||||
return 0;
|
||||
}
|
|
@ -27,6 +27,7 @@
|
|||
#include <subdev/bios/boost.h>
|
||||
#include <subdev/bios/cstep.h>
|
||||
#include <subdev/bios/perf.h>
|
||||
#include <subdev/bios/vpstate.h>
|
||||
#include <subdev/fb.h>
|
||||
#include <subdev/therm.h>
|
||||
#include <subdev/volt.h>
|
||||
|
@ -74,6 +75,88 @@ nvkm_clk_adjust(struct nvkm_clk *clk, bool adjust,
|
|||
/******************************************************************************
|
||||
* C-States
|
||||
*****************************************************************************/
|
||||
static bool
|
||||
nvkm_cstate_valid(struct nvkm_clk *clk, struct nvkm_cstate *cstate,
|
||||
u32 max_volt, int temp)
|
||||
{
|
||||
const struct nvkm_domain *domain = clk->domains;
|
||||
struct nvkm_volt *volt = clk->subdev.device->volt;
|
||||
int voltage;
|
||||
|
||||
while (domain && domain->name != nv_clk_src_max) {
|
||||
if (domain->flags & NVKM_CLK_DOM_FLAG_VPSTATE) {
|
||||
u32 freq = cstate->domain[domain->name];
|
||||
switch (clk->boost_mode) {
|
||||
case NVKM_CLK_BOOST_NONE:
|
||||
if (clk->base_khz && freq > clk->base_khz)
|
||||
return false;
|
||||
case NVKM_CLK_BOOST_BIOS:
|
||||
if (clk->boost_khz && freq > clk->boost_khz)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
domain++;
|
||||
}
|
||||
|
||||
if (!volt)
|
||||
return true;
|
||||
|
||||
voltage = nvkm_volt_map(volt, cstate->voltage, temp);
|
||||
if (voltage < 0)
|
||||
return false;
|
||||
return voltage <= min(max_volt, volt->max_uv);
|
||||
}
|
||||
|
||||
static struct nvkm_cstate *
|
||||
nvkm_cstate_find_best(struct nvkm_clk *clk, struct nvkm_pstate *pstate,
|
||||
struct nvkm_cstate *start)
|
||||
{
|
||||
struct nvkm_device *device = clk->subdev.device;
|
||||
struct nvkm_volt *volt = device->volt;
|
||||
struct nvkm_cstate *cstate;
|
||||
int max_volt;
|
||||
|
||||
if (!pstate || !start)
|
||||
return NULL;
|
||||
|
||||
if (!volt)
|
||||
return start;
|
||||
|
||||
max_volt = volt->max_uv;
|
||||
if (volt->max0_id != 0xff)
|
||||
max_volt = min(max_volt,
|
||||
nvkm_volt_map(volt, volt->max0_id, clk->temp));
|
||||
if (volt->max1_id != 0xff)
|
||||
max_volt = min(max_volt,
|
||||
nvkm_volt_map(volt, volt->max1_id, clk->temp));
|
||||
if (volt->max2_id != 0xff)
|
||||
max_volt = min(max_volt,
|
||||
nvkm_volt_map(volt, volt->max2_id, clk->temp));
|
||||
|
||||
for (cstate = start; &cstate->head != &pstate->list;
|
||||
cstate = list_entry(cstate->head.prev, typeof(*cstate), head)) {
|
||||
if (nvkm_cstate_valid(clk, cstate, max_volt, clk->temp))
|
||||
break;
|
||||
}
|
||||
|
||||
return cstate;
|
||||
}
|
||||
|
||||
static struct nvkm_cstate *
|
||||
nvkm_cstate_get(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei)
|
||||
{
|
||||
struct nvkm_cstate *cstate;
|
||||
if (cstatei == NVKM_CLK_CSTATE_HIGHEST)
|
||||
return list_last_entry(&pstate->list, typeof(*cstate), head);
|
||||
else {
|
||||
list_for_each_entry(cstate, &pstate->list, head) {
|
||||
if (cstate->id == cstatei)
|
||||
return cstate;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
nvkm_cstate_prog(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei)
|
||||
{
|
||||
|
@ -85,7 +168,8 @@ nvkm_cstate_prog(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei)
|
|||
int ret;
|
||||
|
||||
if (!list_empty(&pstate->list)) {
|
||||
cstate = list_entry(pstate->list.prev, typeof(*cstate), head);
|
||||
cstate = nvkm_cstate_get(clk, pstate, cstatei);
|
||||
cstate = nvkm_cstate_find_best(clk, pstate, cstate);
|
||||
} else {
|
||||
cstate = &pstate->base;
|
||||
}
|
||||
|
@ -99,7 +183,8 @@ nvkm_cstate_prog(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei)
|
|||
}
|
||||
|
||||
if (volt) {
|
||||
ret = nvkm_volt_set_id(volt, cstate->voltage, +1);
|
||||
ret = nvkm_volt_set_id(volt, cstate->voltage,
|
||||
pstate->base.voltage, clk->temp, +1);
|
||||
if (ret && ret != -ENODEV) {
|
||||
nvkm_error(subdev, "failed to raise voltage: %d\n", ret);
|
||||
return ret;
|
||||
|
@ -113,7 +198,8 @@ nvkm_cstate_prog(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei)
|
|||
}
|
||||
|
||||
if (volt) {
|
||||
ret = nvkm_volt_set_id(volt, cstate->voltage, -1);
|
||||
ret = nvkm_volt_set_id(volt, cstate->voltage,
|
||||
pstate->base.voltage, clk->temp, -1);
|
||||
if (ret && ret != -ENODEV)
|
||||
nvkm_error(subdev, "failed to lower voltage: %d\n", ret);
|
||||
}
|
||||
|
@ -138,6 +224,7 @@ static int
|
|||
nvkm_cstate_new(struct nvkm_clk *clk, int idx, struct nvkm_pstate *pstate)
|
||||
{
|
||||
struct nvkm_bios *bios = clk->subdev.device->bios;
|
||||
struct nvkm_volt *volt = clk->subdev.device->volt;
|
||||
const struct nvkm_domain *domain = clk->domains;
|
||||
struct nvkm_cstate *cstate = NULL;
|
||||
struct nvbios_cstepX cstepX;
|
||||
|
@ -148,12 +235,16 @@ nvkm_cstate_new(struct nvkm_clk *clk, int idx, struct nvkm_pstate *pstate)
|
|||
if (!data)
|
||||
return -ENOENT;
|
||||
|
||||
if (volt && nvkm_volt_map_min(volt, cstepX.voltage) > volt->max_uv)
|
||||
return -EINVAL;
|
||||
|
||||
cstate = kzalloc(sizeof(*cstate), GFP_KERNEL);
|
||||
if (!cstate)
|
||||
return -ENOMEM;
|
||||
|
||||
*cstate = pstate->base;
|
||||
cstate->voltage = cstepX.voltage;
|
||||
cstate->id = idx;
|
||||
|
||||
while (domain && domain->name != nv_clk_src_max) {
|
||||
if (domain->flags & NVKM_CLK_DOM_FLAG_CORE) {
|
||||
|
@ -175,7 +266,7 @@ static int
|
|||
nvkm_pstate_prog(struct nvkm_clk *clk, int pstatei)
|
||||
{
|
||||
struct nvkm_subdev *subdev = &clk->subdev;
|
||||
struct nvkm_ram *ram = subdev->device->fb->ram;
|
||||
struct nvkm_fb *fb = subdev->device->fb;
|
||||
struct nvkm_pci *pci = subdev->device->pci;
|
||||
struct nvkm_pstate *pstate;
|
||||
int ret, idx = 0;
|
||||
|
@ -190,7 +281,8 @@ nvkm_pstate_prog(struct nvkm_clk *clk, int pstatei)
|
|||
|
||||
nvkm_pcie_set_link(pci, pstate->pcie_speed, pstate->pcie_width);
|
||||
|
||||
if (ram && ram->func->calc) {
|
||||
if (fb && fb->ram && fb->ram->func->calc) {
|
||||
struct nvkm_ram *ram = fb->ram;
|
||||
int khz = pstate->base.domain[nv_clk_src_mem];
|
||||
do {
|
||||
ret = ram->func->calc(ram, khz);
|
||||
|
@ -200,7 +292,7 @@ nvkm_pstate_prog(struct nvkm_clk *clk, int pstatei)
|
|||
ram->func->tidy(ram);
|
||||
}
|
||||
|
||||
return nvkm_cstate_prog(clk, pstate, 0);
|
||||
return nvkm_cstate_prog(clk, pstate, NVKM_CLK_CSTATE_HIGHEST);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -214,14 +306,14 @@ nvkm_pstate_work(struct work_struct *work)
|
|||
return;
|
||||
clk->pwrsrc = power_supply_is_system_supplied();
|
||||
|
||||
nvkm_trace(subdev, "P %d PWR %d U(AC) %d U(DC) %d A %d T %d D %d\n",
|
||||
nvkm_trace(subdev, "P %d PWR %d U(AC) %d U(DC) %d A %d T %d°C D %d\n",
|
||||
clk->pstate, clk->pwrsrc, clk->ustate_ac, clk->ustate_dc,
|
||||
clk->astate, clk->tstate, clk->dstate);
|
||||
clk->astate, clk->temp, clk->dstate);
|
||||
|
||||
pstate = clk->pwrsrc ? clk->ustate_ac : clk->ustate_dc;
|
||||
if (clk->state_nr && pstate != -1) {
|
||||
pstate = (pstate < 0) ? clk->astate : pstate;
|
||||
pstate = min(pstate, clk->state_nr - 1 + clk->tstate);
|
||||
pstate = min(pstate, clk->state_nr - 1);
|
||||
pstate = max(pstate, clk->dstate);
|
||||
} else {
|
||||
pstate = clk->pstate = -1;
|
||||
|
@ -448,13 +540,12 @@ nvkm_clk_astate(struct nvkm_clk *clk, int req, int rel, bool wait)
|
|||
}
|
||||
|
||||
int
|
||||
nvkm_clk_tstate(struct nvkm_clk *clk, int req, int rel)
|
||||
nvkm_clk_tstate(struct nvkm_clk *clk, u8 temp)
|
||||
{
|
||||
if (!rel) clk->tstate = req;
|
||||
if ( rel) clk->tstate += rel;
|
||||
clk->tstate = min(clk->tstate, 0);
|
||||
clk->tstate = max(clk->tstate, -(clk->state_nr - 1));
|
||||
return nvkm_pstate_calc(clk, true);
|
||||
if (clk->temp == temp)
|
||||
return 0;
|
||||
clk->temp = temp;
|
||||
return nvkm_pstate_calc(clk, false);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -524,9 +615,9 @@ nvkm_clk_init(struct nvkm_subdev *subdev)
|
|||
return clk->func->init(clk);
|
||||
|
||||
clk->astate = clk->state_nr - 1;
|
||||
clk->tstate = 0;
|
||||
clk->dstate = 0;
|
||||
clk->pstate = -1;
|
||||
clk->temp = 90; /* reasonable default value */
|
||||
nvkm_pstate_calc(clk, true);
|
||||
return 0;
|
||||
}
|
||||
|
@ -561,10 +652,22 @@ int
|
|||
nvkm_clk_ctor(const struct nvkm_clk_func *func, struct nvkm_device *device,
|
||||
int index, bool allow_reclock, struct nvkm_clk *clk)
|
||||
{
|
||||
struct nvkm_subdev *subdev = &clk->subdev;
|
||||
struct nvkm_bios *bios = device->bios;
|
||||
int ret, idx, arglen;
|
||||
const char *mode;
|
||||
struct nvbios_vpstate_header h;
|
||||
|
||||
nvkm_subdev_ctor(&nvkm_clk, device, index, subdev);
|
||||
|
||||
if (bios && !nvbios_vpstate_parse(bios, &h)) {
|
||||
struct nvbios_vpstate_entry base, boost;
|
||||
if (!nvbios_vpstate_entry(bios, &h, h.boost_id, &boost))
|
||||
clk->boost_khz = boost.clock_mhz * 1000;
|
||||
if (!nvbios_vpstate_entry(bios, &h, h.base_id, &base))
|
||||
clk->base_khz = base.clock_mhz * 1000;
|
||||
}
|
||||
|
||||
nvkm_subdev_ctor(&nvkm_clk, device, index, &clk->subdev);
|
||||
clk->func = func;
|
||||
INIT_LIST_HEAD(&clk->states);
|
||||
clk->domains = func->domains;
|
||||
|
@ -607,6 +710,8 @@ nvkm_clk_ctor(const struct nvkm_clk_func *func, struct nvkm_device *device,
|
|||
if (mode)
|
||||
clk->ustate_dc = nvkm_clk_nstate(clk, mode, arglen);
|
||||
|
||||
clk->boost_mode = nvkm_longopt(device->cfgopt, "NvBoost",
|
||||
NVKM_CLK_BOOST_NONE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -457,7 +457,7 @@ gf100_clk = {
|
|||
{ nv_clk_src_hubk06 , 0x00 },
|
||||
{ nv_clk_src_hubk01 , 0x01 },
|
||||
{ nv_clk_src_copy , 0x02 },
|
||||
{ nv_clk_src_gpc , 0x03, 0, "core", 2000 },
|
||||
{ nv_clk_src_gpc , 0x03, NVKM_CLK_DOM_FLAG_VPSTATE, "core", 2000 },
|
||||
{ nv_clk_src_rop , 0x04 },
|
||||
{ nv_clk_src_mem , 0x05, 0, "memory", 1000 },
|
||||
{ nv_clk_src_vdec , 0x06 },
|
||||
|
|
|
@ -491,7 +491,7 @@ gk104_clk = {
|
|||
.domains = {
|
||||
{ nv_clk_src_crystal, 0xff },
|
||||
{ nv_clk_src_href , 0xff },
|
||||
{ nv_clk_src_gpc , 0x00, NVKM_CLK_DOM_FLAG_CORE, "core", 2000 },
|
||||
{ nv_clk_src_gpc , 0x00, NVKM_CLK_DOM_FLAG_CORE | NVKM_CLK_DOM_FLAG_VPSTATE, "core", 2000 },
|
||||
{ nv_clk_src_hubk07 , 0x01, NVKM_CLK_DOM_FLAG_CORE },
|
||||
{ nv_clk_src_rop , 0x02, NVKM_CLK_DOM_FLAG_CORE },
|
||||
{ nv_clk_src_mem , 0x03, 0, "memory", 500 },
|
||||
|
|
|
@ -50,24 +50,33 @@ gf100_fb_intr(struct nvkm_fb *base)
|
|||
}
|
||||
|
||||
int
|
||||
gf100_fb_oneinit(struct nvkm_fb *fb)
|
||||
gf100_fb_oneinit(struct nvkm_fb *base)
|
||||
{
|
||||
struct nvkm_device *device = fb->subdev.device;
|
||||
struct gf100_fb *fb = gf100_fb(base);
|
||||
struct nvkm_device *device = fb->base.subdev.device;
|
||||
int ret, size = 0x1000;
|
||||
|
||||
size = nvkm_longopt(device->cfgopt, "MmuDebugBufferSize", size);
|
||||
size = min(size, 0x1000);
|
||||
|
||||
ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, size, 0x1000,
|
||||
false, &fb->mmu_rd);
|
||||
false, &fb->base.mmu_rd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, size, 0x1000,
|
||||
false, &fb->mmu_wr);
|
||||
false, &fb->base.mmu_wr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
fb->r100c10_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
|
||||
if (fb->r100c10_page) {
|
||||
fb->r100c10 = dma_map_page(device->dev, fb->r100c10_page, 0,
|
||||
PAGE_SIZE, DMA_BIDIRECTIONAL);
|
||||
if (dma_mapping_error(device->dev, fb->r100c10))
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -123,14 +132,6 @@ gf100_fb_new_(const struct nvkm_fb_func *func, struct nvkm_device *device,
|
|||
nvkm_fb_ctor(func, device, index, &fb->base);
|
||||
*pfb = &fb->base;
|
||||
|
||||
fb->r100c10_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
|
||||
if (fb->r100c10_page) {
|
||||
fb->r100c10 = dma_map_page(device->dev, fb->r100c10_page, 0,
|
||||
PAGE_SIZE, DMA_BIDIRECTIONAL);
|
||||
if (dma_mapping_error(device->dev, fb->r100c10))
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -210,6 +210,23 @@ nv50_fb_intr(struct nvkm_fb *base)
|
|||
nvkm_fifo_chan_put(fifo, flags, &chan);
|
||||
}
|
||||
|
||||
static int
|
||||
nv50_fb_oneinit(struct nvkm_fb *base)
|
||||
{
|
||||
struct nv50_fb *fb = nv50_fb(base);
|
||||
struct nvkm_device *device = fb->base.subdev.device;
|
||||
|
||||
fb->r100c08_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
|
||||
if (fb->r100c08_page) {
|
||||
fb->r100c08 = dma_map_page(device->dev, fb->r100c08_page, 0,
|
||||
PAGE_SIZE, DMA_BIDIRECTIONAL);
|
||||
if (dma_mapping_error(device->dev, fb->r100c08))
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
nv50_fb_init(struct nvkm_fb *base)
|
||||
{
|
||||
|
@ -245,6 +262,7 @@ nv50_fb_dtor(struct nvkm_fb *base)
|
|||
static const struct nvkm_fb_func
|
||||
nv50_fb_ = {
|
||||
.dtor = nv50_fb_dtor,
|
||||
.oneinit = nv50_fb_oneinit,
|
||||
.init = nv50_fb_init,
|
||||
.intr = nv50_fb_intr,
|
||||
.ram_new = nv50_fb_ram_new,
|
||||
|
@ -263,16 +281,6 @@ nv50_fb_new_(const struct nv50_fb_func *func, struct nvkm_device *device,
|
|||
fb->func = func;
|
||||
*pfb = &fb->base;
|
||||
|
||||
fb->r100c08_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
|
||||
if (fb->r100c08_page) {
|
||||
fb->r100c08 = dma_map_page(device->dev, fb->r100c08_page, 0,
|
||||
PAGE_SIZE, DMA_BIDIRECTIONAL);
|
||||
if (dma_mapping_error(device->dev, fb->r100c08))
|
||||
return -EFAULT;
|
||||
} else {
|
||||
nvkm_warn(&fb->base.subdev, "failed 100c08 page alloc\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ int gf100_ram_ctor(const struct nvkm_ram_func *, struct nvkm_fb *,
|
|||
int gf100_ram_get(struct nvkm_ram *, u64, u32, u32, u32, struct nvkm_mem **);
|
||||
void gf100_ram_put(struct nvkm_ram *, struct nvkm_mem **);
|
||||
|
||||
int gk104_ram_ctor(struct nvkm_fb *, struct nvkm_ram **, u32);
|
||||
int gk104_ram_init(struct nvkm_ram *ram);
|
||||
|
||||
/* RAM type-specific MR calculation routines */
|
||||
|
|
|
@ -259,7 +259,9 @@ gk104_ram_calc_gddr5(struct gk104_ram *ram, u32 freq)
|
|||
|
||||
ram_mask(fuc, 0x10f808, 0x40000000, 0x40000000);
|
||||
ram_block(fuc);
|
||||
ram_wr32(fuc, 0x62c000, 0x0f0f0000);
|
||||
|
||||
if (nvkm_device_engine(ram->base.fb->subdev.device, NVKM_ENGINE_DISP))
|
||||
ram_wr32(fuc, 0x62c000, 0x0f0f0000);
|
||||
|
||||
/* MR1: turn termination on early, for some reason.. */
|
||||
if ((ram->base.mr[1] & 0x03c) != 0x030) {
|
||||
|
@ -658,7 +660,9 @@ gk104_ram_calc_gddr5(struct gk104_ram *ram, u32 freq)
|
|||
gk104_ram_train(fuc, 0x80020000, 0x01000000);
|
||||
|
||||
ram_unblock(fuc);
|
||||
ram_wr32(fuc, 0x62c000, 0x0f0f0f00);
|
||||
|
||||
if (nvkm_device_engine(ram->base.fb->subdev.device, NVKM_ENGINE_DISP))
|
||||
ram_wr32(fuc, 0x62c000, 0x0f0f0f00);
|
||||
|
||||
if (next->bios.rammap_11_08_01)
|
||||
data = 0x00000800;
|
||||
|
@ -706,7 +710,9 @@ gk104_ram_calc_sddr3(struct gk104_ram *ram, u32 freq)
|
|||
|
||||
ram_mask(fuc, 0x10f808, 0x40000000, 0x40000000);
|
||||
ram_block(fuc);
|
||||
ram_wr32(fuc, 0x62c000, 0x0f0f0000);
|
||||
|
||||
if (nvkm_device_engine(ram->base.fb->subdev.device, NVKM_ENGINE_DISP))
|
||||
ram_wr32(fuc, 0x62c000, 0x0f0f0000);
|
||||
|
||||
if (vc == 1 && ram_have(fuc, gpio2E)) {
|
||||
u32 temp = ram_mask(fuc, gpio2E, 0x3000, fuc->r_func2E[1]);
|
||||
|
@ -936,7 +942,9 @@ gk104_ram_calc_sddr3(struct gk104_ram *ram, u32 freq)
|
|||
ram_nsec(fuc, 1000);
|
||||
|
||||
ram_unblock(fuc);
|
||||
ram_wr32(fuc, 0x62c000, 0x0f0f0f00);
|
||||
|
||||
if (nvkm_device_engine(ram->base.fb->subdev.device, NVKM_ENGINE_DISP))
|
||||
ram_wr32(fuc, 0x62c000, 0x0f0f0f00);
|
||||
|
||||
if (next->bios.rammap_11_08_01)
|
||||
data = 0x00000800;
|
||||
|
@ -1529,6 +1537,12 @@ gk104_ram_func = {
|
|||
|
||||
int
|
||||
gk104_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram)
|
||||
{
|
||||
return gk104_ram_ctor(fb, pram, 0x022554);
|
||||
}
|
||||
|
||||
int
|
||||
gk104_ram_ctor(struct nvkm_fb *fb, struct nvkm_ram **pram, u32 maskaddr)
|
||||
{
|
||||
struct nvkm_subdev *subdev = &fb->subdev;
|
||||
struct nvkm_device *device = subdev->device;
|
||||
|
@ -1544,7 +1558,7 @@ gk104_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram)
|
|||
return -ENOMEM;
|
||||
*pram = &ram->base;
|
||||
|
||||
ret = gf100_ram_ctor(&gk104_ram_func, fb, 0x022554, &ram->base);
|
||||
ret = gf100_ram_ctor(&gk104_ram_func, fb, maskaddr, &ram->base);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
|
@ -23,18 +23,8 @@
|
|||
*/
|
||||
#include "ram.h"
|
||||
|
||||
static const struct nvkm_ram_func
|
||||
gm107_ram_func = {
|
||||
.init = gk104_ram_init,
|
||||
.get = gf100_ram_get,
|
||||
.put = gf100_ram_put,
|
||||
};
|
||||
|
||||
int
|
||||
gm107_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram)
|
||||
{
|
||||
if (!(*pram = kzalloc(sizeof(**pram), GFP_KERNEL)))
|
||||
return -ENOMEM;
|
||||
|
||||
return gf100_ram_ctor(&gm107_ram_func, fb, 0x021c14, *pram);
|
||||
return gk104_ram_ctor(fb, pram, 0x021c14);
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ gk20a_ibus_init_ibus_ring(struct nvkm_subdev *ibus)
|
|||
nvkm_mask(device, 0x137250, 0x3f, 0);
|
||||
|
||||
nvkm_mask(device, 0x000200, 0x20, 0);
|
||||
usleep_range(20, 30);
|
||||
udelay(20);
|
||||
nvkm_mask(device, 0x000200, 0x20, 0x20);
|
||||
|
||||
nvkm_wr32(device, 0x12004c, 0x4);
|
||||
|
|
|
@ -95,61 +95,13 @@ nvkm_iccsense_ina3221_read(struct nvkm_iccsense *iccsense,
|
|||
40 * 8);
|
||||
}
|
||||
|
||||
static void
|
||||
nvkm_iccsense_ina209_config(struct nvkm_iccsense *iccsense,
|
||||
struct nvkm_iccsense_sensor *sensor)
|
||||
{
|
||||
struct nvkm_subdev *subdev = &iccsense->subdev;
|
||||
/* configuration:
|
||||
* 0x0007: 0x0007 shunt and bus continous
|
||||
* 0x0078: 0x0078 128 samples shunt
|
||||
* 0x0780: 0x0780 128 samples bus
|
||||
* 0x1800: 0x0000 +-40 mV shunt range
|
||||
* 0x2000: 0x0000 16V FSR
|
||||
*/
|
||||
u16 value = 0x07ff;
|
||||
nvkm_debug(subdev, "config for sensor id %i: 0x%x\n", sensor->id, value);
|
||||
nv_wr16i2cr(sensor->i2c, sensor->addr, 0x00, value);
|
||||
}
|
||||
|
||||
static void
|
||||
nvkm_iccsense_ina3221_config(struct nvkm_iccsense *iccsense,
|
||||
struct nvkm_iccsense_sensor *sensor)
|
||||
{
|
||||
struct nvkm_subdev *subdev = &iccsense->subdev;
|
||||
/* configuration:
|
||||
* 0x0007: 0x0007 shunt and bus continous
|
||||
* 0x0031: 0x0000 140 us conversion time shunt
|
||||
* 0x01c0: 0x0000 140 us conversion time bus
|
||||
* 0x0f00: 0x0f00 1024 samples
|
||||
* 0x7000: 0x?000 channels
|
||||
*/
|
||||
u16 value = 0x0e07;
|
||||
if (sensor->rail_mask & 0x1)
|
||||
value |= 0x1 << 14;
|
||||
if (sensor->rail_mask & 0x2)
|
||||
value |= 0x1 << 13;
|
||||
if (sensor->rail_mask & 0x4)
|
||||
value |= 0x1 << 12;
|
||||
nvkm_debug(subdev, "config for sensor id %i: 0x%x\n", sensor->id, value);
|
||||
nv_wr16i2cr(sensor->i2c, sensor->addr, 0x00, value);
|
||||
}
|
||||
|
||||
static void
|
||||
nvkm_iccsense_sensor_config(struct nvkm_iccsense *iccsense,
|
||||
struct nvkm_iccsense_sensor *sensor)
|
||||
{
|
||||
switch (sensor->type) {
|
||||
case NVBIOS_EXTDEV_INA209:
|
||||
case NVBIOS_EXTDEV_INA219:
|
||||
nvkm_iccsense_ina209_config(iccsense, sensor);
|
||||
break;
|
||||
case NVBIOS_EXTDEV_INA3221:
|
||||
nvkm_iccsense_ina3221_config(iccsense, sensor);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
struct nvkm_subdev *subdev = &iccsense->subdev;
|
||||
nvkm_trace(subdev, "write config of extdev %i: 0x%04x\n", sensor->id, sensor->config);
|
||||
nv_wr16i2cr(sensor->i2c, sensor->addr, 0x00, sensor->config);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -196,7 +148,6 @@ nvkm_iccsense_dtor(struct nvkm_subdev *subdev)
|
|||
static struct nvkm_iccsense_sensor*
|
||||
nvkm_iccsense_create_sensor(struct nvkm_iccsense *iccsense, u8 id)
|
||||
{
|
||||
|
||||
struct nvkm_subdev *subdev = &iccsense->subdev;
|
||||
struct nvkm_bios *bios = subdev->device->bios;
|
||||
struct nvkm_i2c *i2c = subdev->device->i2c;
|
||||
|
@ -245,7 +196,7 @@ nvkm_iccsense_create_sensor(struct nvkm_iccsense *iccsense, u8 id)
|
|||
sensor->type = extdev.type;
|
||||
sensor->i2c = &i2c_bus->i2c;
|
||||
sensor->addr = addr;
|
||||
sensor->rail_mask = 0x0;
|
||||
sensor->config = 0x0;
|
||||
return sensor;
|
||||
}
|
||||
|
||||
|
@ -273,48 +224,56 @@ nvkm_iccsense_oneinit(struct nvkm_subdev *subdev)
|
|||
|
||||
iccsense->data_valid = true;
|
||||
for (i = 0; i < stbl.nr_entry; ++i) {
|
||||
struct pwr_rail_t *r = &stbl.rail[i];
|
||||
struct nvkm_iccsense_rail *rail;
|
||||
struct pwr_rail_t *pwr_rail = &stbl.rail[i];
|
||||
struct nvkm_iccsense_sensor *sensor;
|
||||
int (*read)(struct nvkm_iccsense *,
|
||||
struct nvkm_iccsense_rail *);
|
||||
int r;
|
||||
|
||||
if (!r->mode || r->resistor_mohm == 0)
|
||||
if (pwr_rail->mode != 1 || !pwr_rail->resistor_count)
|
||||
continue;
|
||||
|
||||
sensor = nvkm_iccsense_get_sensor(iccsense, r->extdev_id);
|
||||
sensor = nvkm_iccsense_get_sensor(iccsense, pwr_rail->extdev_id);
|
||||
if (!sensor)
|
||||
continue;
|
||||
|
||||
switch (sensor->type) {
|
||||
case NVBIOS_EXTDEV_INA209:
|
||||
if (r->rail != 0)
|
||||
continue;
|
||||
read = nvkm_iccsense_ina209_read;
|
||||
break;
|
||||
case NVBIOS_EXTDEV_INA219:
|
||||
if (r->rail != 0)
|
||||
continue;
|
||||
read = nvkm_iccsense_ina219_read;
|
||||
break;
|
||||
case NVBIOS_EXTDEV_INA3221:
|
||||
if (r->rail >= 3)
|
||||
continue;
|
||||
read = nvkm_iccsense_ina3221_read;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
if (!sensor->config)
|
||||
sensor->config = pwr_rail->config;
|
||||
else if (sensor->config != pwr_rail->config)
|
||||
nvkm_error(subdev, "config mismatch found for extdev %i\n", pwr_rail->extdev_id);
|
||||
|
||||
rail = kmalloc(sizeof(*rail), GFP_KERNEL);
|
||||
if (!rail)
|
||||
return -ENOMEM;
|
||||
sensor->rail_mask |= 1 << r->rail;
|
||||
rail->read = read;
|
||||
rail->sensor = sensor;
|
||||
rail->idx = r->rail;
|
||||
rail->mohm = r->resistor_mohm;
|
||||
list_add_tail(&rail->head, &iccsense->rails);
|
||||
for (r = 0; r < pwr_rail->resistor_count; ++r) {
|
||||
struct nvkm_iccsense_rail *rail;
|
||||
struct pwr_rail_resistor_t *res = &pwr_rail->resistors[r];
|
||||
int (*read)(struct nvkm_iccsense *,
|
||||
struct nvkm_iccsense_rail *);
|
||||
|
||||
if (!res->mohm || !res->enabled)
|
||||
continue;
|
||||
|
||||
switch (sensor->type) {
|
||||
case NVBIOS_EXTDEV_INA209:
|
||||
read = nvkm_iccsense_ina209_read;
|
||||
break;
|
||||
case NVBIOS_EXTDEV_INA219:
|
||||
read = nvkm_iccsense_ina219_read;
|
||||
break;
|
||||
case NVBIOS_EXTDEV_INA3221:
|
||||
read = nvkm_iccsense_ina3221_read;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
rail = kmalloc(sizeof(*rail), GFP_KERNEL);
|
||||
if (!rail)
|
||||
return -ENOMEM;
|
||||
|
||||
rail->read = read;
|
||||
rail->sensor = sensor;
|
||||
rail->idx = r;
|
||||
rail->mohm = res->mohm;
|
||||
nvkm_debug(subdev, "create rail for extdev %i: { idx: %i, mohm: %i }\n", pwr_rail->extdev_id, r, rail->mohm);
|
||||
list_add_tail(&rail->head, &iccsense->rails);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ struct nvkm_iccsense_sensor {
|
|||
enum nvbios_extdev_type type;
|
||||
struct i2c_adapter *i2c;
|
||||
u8 addr;
|
||||
u8 rail_mask;
|
||||
u16 config;
|
||||
};
|
||||
|
||||
struct nvkm_iccsense_rail {
|
||||
|
|
|
@ -23,8 +23,8 @@
|
|||
*/
|
||||
#include "mxms.h"
|
||||
|
||||
#define ROM16(x) le16_to_cpu(*(u16 *)&(x))
|
||||
#define ROM32(x) le32_to_cpu(*(u32 *)&(x))
|
||||
#define ROM16(x) get_unaligned_le16(&(x))
|
||||
#define ROM32(x) get_unaligned_le32(&(x))
|
||||
|
||||
static u8 *
|
||||
mxms_data(struct nvkm_mxm *mxm)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
nvkm-y += nvkm/subdev/volt/base.o
|
||||
nvkm-y += nvkm/subdev/volt/gpio.o
|
||||
nvkm-y += nvkm/subdev/volt/nv40.o
|
||||
nvkm-y += nvkm/subdev/volt/gf100.o
|
||||
nvkm-y += nvkm/subdev/volt/gk104.o
|
||||
nvkm-y += nvkm/subdev/volt/gk20a.o
|
||||
nvkm-y += nvkm/subdev/volt/gm20b.o
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <subdev/bios.h>
|
||||
#include <subdev/bios/vmap.h>
|
||||
#include <subdev/bios/volt.h>
|
||||
#include <subdev/therm.h>
|
||||
|
||||
int
|
||||
nvkm_volt_get(struct nvkm_volt *volt)
|
||||
|
@ -50,23 +51,35 @@ static int
|
|||
nvkm_volt_set(struct nvkm_volt *volt, u32 uv)
|
||||
{
|
||||
struct nvkm_subdev *subdev = &volt->subdev;
|
||||
int i, ret = -EINVAL;
|
||||
int i, ret = -EINVAL, best_err = volt->max_uv, best = -1;
|
||||
|
||||
if (volt->func->volt_set)
|
||||
return volt->func->volt_set(volt, uv);
|
||||
|
||||
for (i = 0; i < volt->vid_nr; i++) {
|
||||
if (volt->vid[i].uv == uv) {
|
||||
ret = volt->func->vid_set(volt, volt->vid[i].vid);
|
||||
nvkm_debug(subdev, "set %duv: %d\n", uv, ret);
|
||||
int err = volt->vid[i].uv - uv;
|
||||
if (err < 0 || err > best_err)
|
||||
continue;
|
||||
|
||||
best_err = err;
|
||||
best = i;
|
||||
if (best_err == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (best == -1) {
|
||||
nvkm_error(subdev, "couldn't set %iuv\n", uv);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = volt->func->vid_set(volt, volt->vid[best].vid);
|
||||
nvkm_debug(subdev, "set req %duv to %duv: %d\n", uv,
|
||||
volt->vid[best].uv, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
nvkm_volt_map(struct nvkm_volt *volt, u8 id)
|
||||
int
|
||||
nvkm_volt_map_min(struct nvkm_volt *volt, u8 id)
|
||||
{
|
||||
struct nvkm_bios *bios = volt->subdev.device->bios;
|
||||
struct nvbios_vmap_entry info;
|
||||
|
@ -76,7 +89,7 @@ nvkm_volt_map(struct nvkm_volt *volt, u8 id)
|
|||
vmap = nvbios_vmap_entry_parse(bios, id, &ver, &len, &info);
|
||||
if (vmap) {
|
||||
if (info.link != 0xff) {
|
||||
int ret = nvkm_volt_map(volt, info.link);
|
||||
int ret = nvkm_volt_map_min(volt, info.link);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
info.min += ret;
|
||||
|
@ -88,19 +101,79 @@ nvkm_volt_map(struct nvkm_volt *volt, u8 id)
|
|||
}
|
||||
|
||||
int
|
||||
nvkm_volt_set_id(struct nvkm_volt *volt, u8 id, int condition)
|
||||
nvkm_volt_map(struct nvkm_volt *volt, u8 id, u8 temp)
|
||||
{
|
||||
struct nvkm_bios *bios = volt->subdev.device->bios;
|
||||
struct nvbios_vmap_entry info;
|
||||
u8 ver, len;
|
||||
u16 vmap;
|
||||
|
||||
vmap = nvbios_vmap_entry_parse(bios, id, &ver, &len, &info);
|
||||
if (vmap) {
|
||||
s64 result;
|
||||
|
||||
if (volt->speedo < 0)
|
||||
return volt->speedo;
|
||||
|
||||
if (ver == 0x10 || (ver == 0x20 && info.mode == 0)) {
|
||||
result = div64_s64((s64)info.arg[0], 10);
|
||||
result += div64_s64((s64)info.arg[1] * volt->speedo, 10);
|
||||
result += div64_s64((s64)info.arg[2] * volt->speedo * volt->speedo, 100000);
|
||||
} else if (ver == 0x20) {
|
||||
switch (info.mode) {
|
||||
/* 0x0 handled above! */
|
||||
case 0x1:
|
||||
result = ((s64)info.arg[0] * 15625) >> 18;
|
||||
result += ((s64)info.arg[1] * volt->speedo * 15625) >> 18;
|
||||
result += ((s64)info.arg[2] * temp * 15625) >> 10;
|
||||
result += ((s64)info.arg[3] * volt->speedo * temp * 15625) >> 18;
|
||||
result += ((s64)info.arg[4] * volt->speedo * volt->speedo * 15625) >> 30;
|
||||
result += ((s64)info.arg[5] * temp * temp * 15625) >> 18;
|
||||
break;
|
||||
case 0x3:
|
||||
result = (info.min + info.max) / 2;
|
||||
break;
|
||||
case 0x2:
|
||||
default:
|
||||
result = info.min;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
result = min(max(result, (s64)info.min), (s64)info.max);
|
||||
|
||||
if (info.link != 0xff) {
|
||||
int ret = nvkm_volt_map(volt, info.link, temp);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
result += ret;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
return id ? id * 10000 : -ENODEV;
|
||||
}
|
||||
|
||||
int
|
||||
nvkm_volt_set_id(struct nvkm_volt *volt, u8 id, u8 min_id, u8 temp,
|
||||
int condition)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (volt->func->set_id)
|
||||
return volt->func->set_id(volt, id, condition);
|
||||
|
||||
ret = nvkm_volt_map(volt, id);
|
||||
ret = nvkm_volt_map(volt, id, temp);
|
||||
if (ret >= 0) {
|
||||
int prev = nvkm_volt_get(volt);
|
||||
if (!condition || prev < 0 ||
|
||||
(condition < 0 && ret < prev) ||
|
||||
(condition > 0 && ret > prev)) {
|
||||
int min = nvkm_volt_map(volt, min_id, temp);
|
||||
if (min >= 0)
|
||||
ret = max(min, ret);
|
||||
ret = nvkm_volt_set(volt, ret);
|
||||
} else {
|
||||
ret = 0;
|
||||
|
@ -112,6 +185,7 @@ nvkm_volt_set_id(struct nvkm_volt *volt, u8 id, int condition)
|
|||
static void
|
||||
nvkm_volt_parse_bios(struct nvkm_bios *bios, struct nvkm_volt *volt)
|
||||
{
|
||||
struct nvkm_subdev *subdev = &bios->subdev;
|
||||
struct nvbios_volt_entry ivid;
|
||||
struct nvbios_volt info;
|
||||
u8 ver, hdr, cnt, len;
|
||||
|
@ -119,7 +193,8 @@ nvkm_volt_parse_bios(struct nvkm_bios *bios, struct nvkm_volt *volt)
|
|||
int i;
|
||||
|
||||
data = nvbios_volt_parse(bios, &ver, &hdr, &cnt, &len, &info);
|
||||
if (data && info.vidmask && info.base && info.step) {
|
||||
if (data && info.vidmask && info.base && info.step && info.ranged) {
|
||||
nvkm_debug(subdev, "found ranged based VIDs\n");
|
||||
volt->min_uv = info.min;
|
||||
volt->max_uv = info.max;
|
||||
for (i = 0; i < info.vidmask + 1; i++) {
|
||||
|
@ -132,7 +207,8 @@ nvkm_volt_parse_bios(struct nvkm_bios *bios, struct nvkm_volt *volt)
|
|||
info.base += info.step;
|
||||
}
|
||||
volt->vid_mask = info.vidmask;
|
||||
} else if (data && info.vidmask) {
|
||||
} else if (data && info.vidmask && !info.ranged) {
|
||||
nvkm_debug(subdev, "found entry based VIDs\n");
|
||||
volt->min_uv = 0xffffffff;
|
||||
volt->max_uv = 0;
|
||||
for (i = 0; i < cnt; i++) {
|
||||
|
@ -153,6 +229,14 @@ nvkm_volt_parse_bios(struct nvkm_bios *bios, struct nvkm_volt *volt)
|
|||
}
|
||||
}
|
||||
|
||||
static int
|
||||
nvkm_volt_speedo_read(struct nvkm_volt *volt)
|
||||
{
|
||||
if (volt->func->speedo_read)
|
||||
return volt->func->speedo_read(volt);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int
|
||||
nvkm_volt_init(struct nvkm_subdev *subdev)
|
||||
{
|
||||
|
@ -167,6 +251,21 @@ nvkm_volt_init(struct nvkm_subdev *subdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nvkm_volt_oneinit(struct nvkm_subdev *subdev)
|
||||
{
|
||||
struct nvkm_volt *volt = nvkm_volt(subdev);
|
||||
|
||||
volt->speedo = nvkm_volt_speedo_read(volt);
|
||||
if (volt->speedo > 0)
|
||||
nvkm_debug(&volt->subdev, "speedo %x\n", volt->speedo);
|
||||
|
||||
if (volt->func->oneinit)
|
||||
return volt->func->oneinit(volt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *
|
||||
nvkm_volt_dtor(struct nvkm_subdev *subdev)
|
||||
{
|
||||
|
@ -177,6 +276,7 @@ static const struct nvkm_subdev_func
|
|||
nvkm_volt = {
|
||||
.dtor = nvkm_volt_dtor,
|
||||
.init = nvkm_volt_init,
|
||||
.oneinit = nvkm_volt_oneinit,
|
||||
};
|
||||
|
||||
void
|
||||
|
@ -191,9 +291,22 @@ nvkm_volt_ctor(const struct nvkm_volt_func *func, struct nvkm_device *device,
|
|||
|
||||
/* Assuming the non-bios device should build the voltage table later */
|
||||
if (bios) {
|
||||
u8 ver, hdr, cnt, len;
|
||||
struct nvbios_vmap vmap;
|
||||
|
||||
nvkm_volt_parse_bios(bios, volt);
|
||||
nvkm_debug(&volt->subdev, "min: %iuv max: %iuv\n",
|
||||
volt->min_uv, volt->max_uv);
|
||||
|
||||
if (nvbios_vmap_parse(bios, &ver, &hdr, &cnt, &len, &vmap)) {
|
||||
volt->max0_id = vmap.max0;
|
||||
volt->max1_id = vmap.max1;
|
||||
volt->max2_id = vmap.max2;
|
||||
} else {
|
||||
volt->max0_id = 0xff;
|
||||
volt->max1_id = 0xff;
|
||||
volt->max2_id = 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
if (volt->vid_nr) {
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright 2016 Karol Herbst
|
||||
*
|
||||
* 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: Karol Herbst
|
||||
*/
|
||||
#include "priv.h"
|
||||
|
||||
#include <subdev/fuse.h>
|
||||
|
||||
static int
|
||||
gf100_volt_speedo_read(struct nvkm_volt *volt)
|
||||
{
|
||||
struct nvkm_device *device = volt->subdev.device;
|
||||
struct nvkm_fuse *fuse = device->fuse;
|
||||
|
||||
if (!fuse)
|
||||
return -EINVAL;
|
||||
|
||||
return nvkm_fuse_read(fuse, 0x1cc);
|
||||
}
|
||||
|
||||
int
|
||||
gf100_volt_oneinit(struct nvkm_volt *volt)
|
||||
{
|
||||
struct nvkm_subdev *subdev = &volt->subdev;
|
||||
if (volt->speedo <= 0)
|
||||
nvkm_error(subdev, "couldn't find speedo value, volting not "
|
||||
"possible\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct nvkm_volt_func
|
||||
gf100_volt = {
|
||||
.oneinit = gf100_volt_oneinit,
|
||||
.vid_get = nvkm_voltgpio_get,
|
||||
.vid_set = nvkm_voltgpio_set,
|
||||
.speedo_read = gf100_volt_speedo_read,
|
||||
};
|
||||
|
||||
int
|
||||
gf100_volt_new(struct nvkm_device *device, int index, struct nvkm_volt **pvolt)
|
||||
{
|
||||
struct nvkm_volt *volt;
|
||||
int ret;
|
||||
|
||||
ret = nvkm_volt_new_(&gf100_volt, device, index, &volt);
|
||||
*pvolt = volt;
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return nvkm_voltgpio_init(volt);
|
||||
}
|
|
@ -27,6 +27,7 @@
|
|||
#include <subdev/gpio.h>
|
||||
#include <subdev/bios.h>
|
||||
#include <subdev/bios/volt.h>
|
||||
#include <subdev/fuse.h>
|
||||
|
||||
#define gk104_volt(p) container_of((p), struct gk104_volt, base)
|
||||
struct gk104_volt {
|
||||
|
@ -64,13 +65,33 @@ gk104_volt_set(struct nvkm_volt *base, u32 uv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
gk104_volt_speedo_read(struct nvkm_volt *volt)
|
||||
{
|
||||
struct nvkm_device *device = volt->subdev.device;
|
||||
struct nvkm_fuse *fuse = device->fuse;
|
||||
int ret;
|
||||
|
||||
if (!fuse)
|
||||
return -EINVAL;
|
||||
|
||||
nvkm_wr32(device, 0x122634, 0x0);
|
||||
ret = nvkm_fuse_read(fuse, 0x3a8);
|
||||
nvkm_wr32(device, 0x122634, 0x41);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct nvkm_volt_func
|
||||
gk104_volt_pwm = {
|
||||
.oneinit = gf100_volt_oneinit,
|
||||
.volt_get = gk104_volt_get,
|
||||
.volt_set = gk104_volt_set,
|
||||
.speedo_read = gk104_volt_speedo_read,
|
||||
}, gk104_volt_gpio = {
|
||||
.oneinit = gf100_volt_oneinit,
|
||||
.vid_get = nvkm_voltgpio_get,
|
||||
.vid_set = nvkm_voltgpio_set,
|
||||
.speedo_read = gk104_volt_speedo_read,
|
||||
};
|
||||
|
||||
int
|
||||
|
|
|
@ -9,11 +9,13 @@ int nvkm_volt_new_(const struct nvkm_volt_func *, struct nvkm_device *,
|
|||
int index, struct nvkm_volt **);
|
||||
|
||||
struct nvkm_volt_func {
|
||||
int (*oneinit)(struct nvkm_volt *);
|
||||
int (*volt_get)(struct nvkm_volt *);
|
||||
int (*volt_set)(struct nvkm_volt *, u32 uv);
|
||||
int (*vid_get)(struct nvkm_volt *);
|
||||
int (*vid_set)(struct nvkm_volt *, u8 vid);
|
||||
int (*set_id)(struct nvkm_volt *, u8 id, int condition);
|
||||
int (*speedo_read)(struct nvkm_volt *);
|
||||
};
|
||||
|
||||
int nvkm_voltgpio_init(struct nvkm_volt *);
|
||||
|
@ -23,4 +25,6 @@ int nvkm_voltgpio_set(struct nvkm_volt *, u8);
|
|||
int nvkm_voltpwm_init(struct nvkm_volt *volt);
|
||||
int nvkm_voltpwm_get(struct nvkm_volt *volt);
|
||||
int nvkm_voltpwm_set(struct nvkm_volt *volt, u32 uv);
|
||||
|
||||
int gf100_volt_oneinit(struct nvkm_volt *);
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue