Commit fb422950 authored by Dave Airlie's avatar Dave Airlie

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
  ...
parents 220196b3 2ecf7c43
...@@ -22,6 +22,7 @@ nouveau-$(CONFIG_DEBUG_FS) += nouveau_debugfs.o ...@@ -22,6 +22,7 @@ nouveau-$(CONFIG_DEBUG_FS) += nouveau_debugfs.o
nouveau-y += nouveau_drm.o nouveau-y += nouveau_drm.o
nouveau-y += nouveau_hwmon.o nouveau-y += nouveau_hwmon.o
nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o
nouveau-$(CONFIG_LEDS_CLASS) += nouveau_led.o
nouveau-y += nouveau_nvif.o nouveau-y += nouveau_nvif.o
nouveau-$(CONFIG_NOUVEAU_PLATFORM_DRIVER) += nouveau_platform.o nouveau-$(CONFIG_NOUVEAU_PLATFORM_DRIVER) += nouveau_platform.o
nouveau-y += nouveau_usif.o # userspace <-> nvif nouveau-y += nouveau_usif.o # userspace <-> nvif
......
...@@ -6,6 +6,7 @@ enum dcb_gpio_func_name { ...@@ -6,6 +6,7 @@ enum dcb_gpio_func_name {
DCB_GPIO_TVDAC1 = 0x2d, DCB_GPIO_TVDAC1 = 0x2d,
DCB_GPIO_FAN = 0x09, DCB_GPIO_FAN = 0x09,
DCB_GPIO_FAN_SENSE = 0x3d, DCB_GPIO_FAN_SENSE = 0x3d,
DCB_GPIO_LOGO_LED_PWM = 0x84,
DCB_GPIO_UNUSED = 0xff, DCB_GPIO_UNUSED = 0xff,
DCB_GPIO_VID0 = 0x04, DCB_GPIO_VID0 = 0x04,
DCB_GPIO_VID1 = 0x05, DCB_GPIO_VID1 = 0x05,
......
#ifndef __NVBIOS_ICCSENSE_H__ #ifndef __NVBIOS_ICCSENSE_H__
#define __NVBIOS_ICCSENSE_H__ #define __NVBIOS_ICCSENSE_H__
struct pwr_rail_resistor_t {
u8 mohm;
bool enabled;
};
struct pwr_rail_t { struct pwr_rail_t {
u8 mode; u8 mode;
u8 extdev_id; u8 extdev_id;
u8 resistor_mohm; u8 resistor_count;
u8 rail; struct pwr_rail_resistor_t resistors[3];
u16 config;
}; };
struct nvbios_iccsense { struct nvbios_iccsense {
......
#ifndef __NVBIOS_VMAP_H__ #ifndef __NVBIOS_VMAP_H__
#define __NVBIOS_VMAP_H__ #define __NVBIOS_VMAP_H__
struct nvbios_vmap { struct nvbios_vmap {
u8 max0;
u8 max1;
u8 max2;
}; };
u16 nvbios_vmap_table(struct nvkm_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len); 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, ...@@ -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 *);
struct nvbios_vmap_entry { struct nvbios_vmap_entry {
u8 unk0; u8 mode;
u8 link; u8 link;
u32 min; u32 min;
u32 max; u32 max;
......
...@@ -13,8 +13,9 @@ struct nvbios_volt { ...@@ -13,8 +13,9 @@ struct nvbios_volt {
u32 base; u32 base;
/* GPIO mode */ /* GPIO mode */
u8 vidmask; bool ranged;
s16 step; u8 vidmask;
s16 step;
/* PWM mode */ /* PWM mode */
u32 pwm_freq; u32 pwm_freq;
......
#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 @@ ...@@ -6,6 +6,10 @@
struct nvbios_pll; struct nvbios_pll;
struct nvkm_pll_vals; 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 { enum nv_clk_src {
nv_clk_src_crystal, nv_clk_src_crystal,
nv_clk_src_href, nv_clk_src_href,
...@@ -52,6 +56,7 @@ struct nvkm_cstate { ...@@ -52,6 +56,7 @@ struct nvkm_cstate {
struct list_head head; struct list_head head;
u8 voltage; u8 voltage;
u32 domain[nv_clk_src_max]; u32 domain[nv_clk_src_max];
u8 id;
}; };
struct nvkm_pstate { struct nvkm_pstate {
...@@ -67,7 +72,8 @@ struct nvkm_pstate { ...@@ -67,7 +72,8 @@ struct nvkm_pstate {
struct nvkm_domain { struct nvkm_domain {
enum nv_clk_src name; enum nv_clk_src name;
u8 bios; /* 0xff for none */ 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; u8 flags;
const char *mname; const char *mname;
int mdiv; int mdiv;
...@@ -93,10 +99,16 @@ struct nvkm_clk { ...@@ -93,10 +99,16 @@ struct nvkm_clk {
int ustate_ac; /* user-requested (-1 disabled, -2 perfmon) */ int ustate_ac; /* user-requested (-1 disabled, -2 perfmon) */
int ustate_dc; /* user-requested (-1 disabled, -2 perfmon) */ int ustate_dc; /* user-requested (-1 disabled, -2 perfmon) */
int astate; /* perfmon adjustment (base) */ int astate; /* perfmon adjustment (base) */
int tstate; /* thermal adjustment (max-) */
int dstate; /* display adjustment (min+) */ int dstate; /* display adjustment (min+) */
u8 temp;
bool allow_reclock; 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 /*XXX: die, these are here *only* to support the completely
* bat-shit insane what-was-nouveau_hw.c code * bat-shit insane what-was-nouveau_hw.c code
...@@ -110,7 +122,7 @@ int nvkm_clk_read(struct nvkm_clk *, enum nv_clk_src); ...@@ -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_ustate(struct nvkm_clk *, int req, int pwr);
int nvkm_clk_astate(struct nvkm_clk *, int req, int rel, bool wait); 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_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 nv04_clk_new(struct nvkm_device *, int, struct nvkm_clk **);
int nv40_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 { ...@@ -15,12 +15,28 @@ struct nvkm_volt {
u32 max_uv; u32 max_uv;
u32 min_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_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 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 gk104_volt_new(struct nvkm_device *, int, struct nvkm_volt **);
int gk20a_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 **); int gm20b_volt_new(struct nvkm_device *, int, struct nvkm_volt **);
......
...@@ -232,6 +232,7 @@ nouveau_backlight_init(struct drm_device *dev) ...@@ -232,6 +232,7 @@ nouveau_backlight_init(struct drm_device *dev)
case NV_DEVICE_INFO_V0_TESLA: case NV_DEVICE_INFO_V0_TESLA:
case NV_DEVICE_INFO_V0_FERMI: case NV_DEVICE_INFO_V0_FERMI:
case NV_DEVICE_INFO_V0_KEPLER: case NV_DEVICE_INFO_V0_KEPLER:
case NV_DEVICE_INFO_V0_MAXWELL:
return nv50_backlight_init(connector); return nv50_backlight_init(connector);
default: default:
break; break;
......
...@@ -31,10 +31,8 @@ ...@@ -31,10 +31,8 @@
#define DCB_LOC_ON_CHIP 0 #define DCB_LOC_ON_CHIP 0
#define ROM16(x) le16_to_cpu(*(u16 *)&(x)) #define ROM16(x) get_unaligned_le16(&(x))
#define ROM32(x) le32_to_cpu(*(u32 *)&(x)) #define ROM32(x) get_unaligned_le32(&(x))
#define ROM48(x) ({ u8 *p = &(x); (u64)ROM16(p[4]) << 32 | ROM32(p[0]); })
#define ROM64(x) le64_to_cpu(*(u64 *)&(x))
#define ROMPTR(d,x) ({ \ #define ROMPTR(d,x) ({ \
struct nouveau_drm *drm = nouveau_drm((d)); \ struct nouveau_drm *drm = nouveau_drm((d)); \
ROM16(x) ? &drm->vbios.data[ROM16(x)] : NULL; \ ROM16(x) ? &drm->vbios.data[ROM16(x)] : NULL; \
......
...@@ -47,6 +47,7 @@ ...@@ -47,6 +47,7 @@
#include "nouveau_ttm.h" #include "nouveau_ttm.h"
#include "nouveau_gem.h" #include "nouveau_gem.h"
#include "nouveau_vga.h" #include "nouveau_vga.h"
#include "nouveau_led.h"
#include "nouveau_hwmon.h" #include "nouveau_hwmon.h"
#include "nouveau_acpi.h" #include "nouveau_acpi.h"
#include "nouveau_bios.h" #include "nouveau_bios.h"
...@@ -475,6 +476,7 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) ...@@ -475,6 +476,7 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags)
nouveau_hwmon_init(dev); nouveau_hwmon_init(dev);
nouveau_accel_init(drm); nouveau_accel_init(drm);
nouveau_fbcon_init(dev); nouveau_fbcon_init(dev);
nouveau_led_init(dev);
if (nouveau_runtime_pm != 0) { if (nouveau_runtime_pm != 0) {
pm_runtime_use_autosuspend(dev->dev); pm_runtime_use_autosuspend(dev->dev);
...@@ -510,6 +512,7 @@ nouveau_drm_unload(struct drm_device *dev) ...@@ -510,6 +512,7 @@ nouveau_drm_unload(struct drm_device *dev)
pm_runtime_forbid(dev->dev); pm_runtime_forbid(dev->dev);
} }
nouveau_led_fini(dev);
nouveau_fbcon_fini(dev); nouveau_fbcon_fini(dev);
nouveau_accel_fini(drm); nouveau_accel_fini(drm);
nouveau_hwmon_fini(dev); nouveau_hwmon_fini(dev);
...@@ -561,6 +564,8 @@ nouveau_do_suspend(struct drm_device *dev, bool runtime) ...@@ -561,6 +564,8 @@ nouveau_do_suspend(struct drm_device *dev, bool runtime)
struct nouveau_cli *cli; struct nouveau_cli *cli;
int ret; int ret;
nouveau_led_suspend(dev);
if (dev->mode_config.num_crtc) { if (dev->mode_config.num_crtc) {
NV_INFO(drm, "suspending console...\n"); NV_INFO(drm, "suspending console...\n");
nouveau_fbcon_set_suspend(dev, 1); nouveau_fbcon_set_suspend(dev, 1);
...@@ -649,6 +654,8 @@ nouveau_do_resume(struct drm_device *dev, bool runtime) ...@@ -649,6 +654,8 @@ nouveau_do_resume(struct drm_device *dev, bool runtime)
nouveau_fbcon_set_suspend(dev, 0); nouveau_fbcon_set_suspend(dev, 0);
} }
nouveau_led_resume(dev);
return 0; return 0;
} }
......
...@@ -166,6 +166,9 @@ struct nouveau_drm { ...@@ -166,6 +166,9 @@ struct nouveau_drm {
struct nouveau_hwmon *hwmon; struct nouveau_hwmon *hwmon;
struct nouveau_debugfs *debugfs; struct nouveau_debugfs *debugfs;
/* led management */
struct nouveau_led *led;
/* display power reference */ /* display power reference */
bool have_disp_power_ref; bool have_disp_power_ref;
......
/*
* 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;
}
}
/*
* 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 @@ ...@@ -20,6 +20,7 @@
* DEALINGS IN THE SOFTWARE. * DEALINGS IN THE SOFTWARE.
*/ */
#include <core/device.h> #include <core/device.h>
#include <core/firmware.h>
/** /**
* nvkm_firmware_get - load firmware from the official nvidia/chip/ directory * nvkm_firmware_get - load firmware from the official nvidia/chip/ directory
......
...@@ -1357,7 +1357,7 @@ nvc0_chipset = { ...@@ -1357,7 +1357,7 @@ nvc0_chipset = {
.pmu = gf100_pmu_new, .pmu = gf100_pmu_new,
.therm = gt215_therm_new, .therm = gt215_therm_new,
.timer = nv41_timer_new, .timer = nv41_timer_new,
.volt = nv40_volt_new, .volt = gf100_volt_new,
.ce[0] = gf100_ce_new, .ce[0] = gf100_ce_new,
.ce[1] = gf100_ce_new, .ce[1] = gf100_ce_new,
.disp = gt215_disp_new, .disp = gt215_disp_new,
...@@ -1394,7 +1394,7 @@ nvc1_chipset = { ...@@ -1394,7 +1394,7 @@ nvc1_chipset = {
.pmu = gf100_pmu_new, .pmu = gf100_pmu_new,
.therm = gt215_therm_new, .therm = gt215_therm_new,
.timer = nv41_timer_new, .timer = nv41_timer_new,
.volt = nv40_volt_new, .volt = gf100_volt_new,
.ce[0] = gf100_ce_new, .ce[0] = gf100_ce_new,
.disp = gt215_disp_new, .disp = gt215_disp_new,
.dma = gf100_dma_new, .dma = gf100_dma_new,
...@@ -1430,7 +1430,7 @@ nvc3_chipset = { ...@@ -1430,7 +1430,7 @@ nvc3_chipset = {
.pmu = gf100_pmu_new, .pmu = gf100_pmu_new,
.therm = gt215_therm_new, .therm = gt215_therm_new,
.timer = nv41_timer_new, .timer = nv41_timer_new,
.volt = nv40_volt_new, .volt = gf100_volt_new,
.ce[0] = gf100_ce_new, .ce[0] = gf100_ce_new,
.disp = gt215_disp_new, .disp = gt215_disp_new,
.dma = gf100_dma_new, .dma = gf100_dma_new,
...@@ -1466,7 +1466,7 @@ nvc4_chipset = { ...@@ -1466,7 +1466,7 @@ nvc4_chipset = {
.pmu = gf100_pmu_new, .pmu = gf100_pmu_new,
.therm = gt215_therm_new, .therm = gt215_therm_new,
.timer = nv41_timer_new, .timer = nv41_timer_new,
.volt = nv40_volt_new, .volt = gf100_volt_new,
.ce[0] = gf100_ce_new, .ce[0] = gf100_ce_new,
.ce[1] = gf100_ce_new, .ce[1] = gf100_ce_new,
.disp = gt215_disp_new, .disp = gt215_disp_new,
...@@ -1503,7 +1503,7 @@ nvc8_chipset = { ...@@ -1503,7 +1503,7 @@ nvc8_chipset = {
.pmu = gf100_pmu_new, .pmu = gf100_pmu_new,
.therm = gt215_therm_new, .therm = gt215_therm_new,
.timer = nv41_timer_new, .timer = nv41_timer_new,
.volt = nv40_volt_new, .volt = gf100_volt_new,
.ce[0] = gf100_ce_new, .ce[0] = gf100_ce_new,
.ce[1] = gf100_ce_new, .ce[1] = gf100_ce_new,
.disp = gt215_disp_new, .disp = gt215_disp_new,
...@@ -1540,7 +1540,7 @@ nvce_chipset = { ...@@ -1540,7 +1540,7 @@ nvce_chipset = {
.pmu = gf100_pmu_new, .pmu = gf100_pmu_new,
.therm = gt215_therm_new, .therm = gt215_therm_new,
.timer = nv41_timer_new, .timer = nv41_timer_new,
.volt = nv40_volt_new, .volt = gf100_volt_new,
.ce[0] = gf100_ce_new, .ce[0] = gf100_ce_new,
.ce[1] = gf100_ce_new, .ce[1] = gf100_ce_new,
.disp = gt215_disp_new, .disp = gt215_disp_new,
...@@ -1577,7 +1577,7 @@ nvcf_chipset = { ...@@ -1577,7 +1577,7 @@ nvcf_chipset = {
.pmu = gf100_pmu_new, .pmu = gf100_pmu_new,
.therm = gt215_therm_new, .therm = gt215_therm_new,
.timer = nv41_timer_new, .timer = nv41_timer_new,
.volt = nv40_volt_new, .volt = gf100_volt_new,
.ce[0] = gf100_ce_new, .ce[0] = gf100_ce_new,
.disp = gt215_disp_new, .disp = gt215_disp_new,
.dma = gf100_dma_new, .dma = gf100_dma_new,
...@@ -1612,6 +1612,7 @@ nvd7_chipset = { ...@@ -1612,6 +1612,7 @@ nvd7_chipset = {
.pci = gf106_pci_new, .pci = gf106_pci_new,
.therm = gf119_therm_new, .therm = gf119_therm_new,
.timer = nv41_timer_new, .timer = nv41_timer_new,
.volt = gf100_volt_new,
.ce[0] = gf100_ce_new, .ce[0] = gf100_ce_new,
.disp = gf119_disp_new, .disp = gf119_disp_new,
.dma = gf119_dma_new, .dma = gf119_dma_new,
...@@ -1647,7 +1648,7 @@ nvd9_chipset = { ...@@ -1647,7 +1648,7 @@ nvd9_chipset = {
.pmu = gf119_pmu_new, .pmu = gf119_pmu_new,
.therm = gf119_therm_new, .therm = gf119_therm_new,
.timer = nv41_timer_new, .timer = nv41_timer_new,
.volt = nv40_volt_new, .volt = gf100_volt_new,
.ce[0] = gf100_ce_new, .ce[0] = gf100_ce_new,
.disp = gf119_disp_new, .disp = gf119_disp_new,
.dma = gf119_dma_new, .dma = gf119_dma_new,
......
...@@ -1665,14 +1665,31 @@ nvkm_device_pci_new(struct pci_dev *pci_dev, const char *cfg, const char *dbg, ...@@ -1665,14 +1665,31 @@ nvkm_device_pci_new(struct pci_dev *pci_dev, const char *cfg, const char *dbg,
*pdevice = &pdev->device; *pdevice = &pdev->device;
pdev->pdev = pci_dev; pdev->pdev = pci_dev;
return nvkm_device_ctor(&nvkm_device_pci_func, quirk, &pci_dev->dev, ret = nvkm_device_ctor(&nvkm_device_pci_func, quirk, &pci_dev->dev,
pci_is_pcie(pci_dev) ? NVKM_DEVICE_PCIE : pci_is_pcie(pci_dev) ? NVKM_DEVICE_PCIE :
pci_find_capability(pci_dev, PCI_CAP_ID_AGP) ? pci_find_capability(pci_dev, PCI_CAP_ID_AGP) ?
NVKM_DEVICE_AGP : NVKM_DEVICE_PCI, NVKM_DEVICE_AGP : NVKM_DEVICE_PCI,
(u64)pci_domain_nr(pci_dev->bus) << 32 | (u64)pci_domain_nr(pci_dev->bus) << 32 |
pci_dev->bus->number << 16 | pci_dev->bus->number << 16 |
PCI_SLOT(pci_dev->devfn) << 8 | PCI_SLOT(pci_dev->devfn) << 8 |
PCI_FUNC(pci_dev->devfn), name, PCI_FUNC(pci_dev->devfn), name,
cfg, dbg, detect, mmio, subdev_mask, cfg, dbg, detect, mmio, subdev_mask,
&pdev->device); &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 ...@@ -45,14 +45,6 @@ static const struct nvkm_output_func
g94_sor_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 * DisplayPort
******************************************************************************/ ******************************************************************************/
......
...@@ -187,6 +187,7 @@ nv30_gr = { ...@@ -187,6 +187,7 @@ nv30_gr = {
{ -1, -1, 0x038a, &nv04_gr_object }, /* ifc (nv30) */ { -1, -1, 0x038a, &nv04_gr_object }, /* ifc (nv30) */
{ -1, -1, 0x039e, &nv04_gr_object }, /* swzsurf (nv30) */ { -1, -1, 0x039e, &nv04_gr_object }, /* swzsurf (nv30) */
{ -1, -1, 0x0397, &nv04_gr_object }, /* rankine */ { -1, -1, 0x0397, &nv04_gr_object }, /* rankine */
{ -1, -1, 0x0597, &nv04_gr_object }, /* kelvin */
{} {}
} }
}; };
......
...@@ -123,6 +123,7 @@ nv34_gr = { ...@@ -123,6 +123,7 @@ nv34_gr = {
{ -1, -1, 0x0389, &nv04_gr_object }, /* sifm (nv30) */ { -1, -1, 0x0389, &nv04_gr_object }, /* sifm (nv30) */
{ -1, -1, 0x038a, &nv04_gr_object }, /* ifc (nv30) */ { -1, -1, 0x038a, &nv04_gr_object }, /* ifc (nv30) */
{ -1, -1, 0x039e, &nv04_gr_object }, /* swzsurf (nv30) */ { -1, -1, 0x039e, &nv04_gr_object }, /* swzsurf (nv30) */
{ -1, -1, 0x0597, &nv04_gr_object }, /* kelvin */
{ -1, -1, 0x0697, &nv04_gr_object }, /* rankine */ { -1, -1, 0x0697, &nv04_gr_object }, /* rankine */
{} {}
} }
......
...@@ -124,6 +124,7 @@ nv35_gr = { ...@@ -124,6 +124,7 @@ nv35_gr = {
{ -1, -1, 0x038a, &nv04_gr_object }, /* ifc (nv30) */ { -1, -1, 0x038a, &nv04_gr_object }, /* ifc (nv30) */
{ -1, -1, 0x039e, &nv04_gr_object }, /* swzsurf (nv30) */ { -1, -1, 0x039e, &nv04_gr_object }, /* swzsurf (nv30) */
{ -1, -1, 0x0497, &nv04_gr_object }, /* rankine */ { -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) ...@@ -84,7 +84,7 @@ nv50_bar_oneinit(struct nvkm_bar *base)
start = 0x0100000000ULL; start = 0x0100000000ULL;
limit = start + device->func->resource_size(device, 3); 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) if (ret)
return ret; return ret;
...@@ -117,7 +117,7 @@ nv50_bar_oneinit(struct nvkm_bar *base) ...@@ -117,7 +117,7 @@ nv50_bar_oneinit(struct nvkm_bar *base)
start = 0x0000000000ULL; start = 0x0000000000ULL;
limit = start + device->func->resource_size(device, 1); 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) if (ret)
return ret; return ret;
......
...@@ -31,6 +31,7 @@ nvkm-y += nvkm/subdev/bios/timing.o ...@@ -31,6 +31,7 @@ nvkm-y += nvkm/subdev/bios/timing.o
nvkm-y += nvkm/subdev/bios/therm.o nvkm-y += nvkm/subdev/bios/therm.o
nvkm-y += nvkm/subdev/bios/vmap.o nvkm-y += nvkm/subdev/bios/vmap.o
nvkm-y += nvkm/subdev/bios/volt.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/xpio.o
nvkm-y += nvkm/subdev/bios/M0203.o nvkm-y += nvkm/subdev/bios/M0203.o
nvkm-y += nvkm/subdev/bios/M0205.o nvkm-y += nvkm/subdev/bios/M0205.o
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
*/ */
#include <subdev/bios.h> #include <subdev/bios.h>
#include <subdev/bios/bit.h> #include <subdev/bios/bit.h>
#include <subdev/bios/extdev.h>
#include <subdev/bios/iccsense.h> #include <subdev/bios/iccsense.h>
static u16 static u16
...@@ -77,23 +78,47 @@ nvbios_iccsense_parse(struct nvkm_bios *bios, struct nvbios_iccsense *iccsense) ...@@ -77,23 +78,47 @@ nvbios_iccsense_parse(struct nvkm_bios *bios, struct nvbios_iccsense *iccsense)
return -ENOMEM; return -ENOMEM;
for (i = 0; i < cnt; ++i) { for (i = 0; i < cnt; ++i) {
struct nvbios_extdev_func extdev;
struct pwr_rail_t *rail = &iccsense->rail[i]; struct pwr_rail_t *rail = &iccsense->rail[i];
u8 res_start = 0;
int r;
entry = table + hdr + i * len; entry = table + hdr + i * len;
switch(ver) { switch(ver) {
case 0x10: case 0x10:
rail->mode = nvbios_rd08(bios, entry + 0x1); rail->mode = nvbios_rd08(bios, entry + 0x1);
rail->extdev_id = nvbios_rd08(bios, entry + 0x2); rail->extdev_id = nvbios_rd08(bios, entry + 0x2);
rail->resistor_mohm = nvbios_rd08(bios, entry + 0x3); res_start = 0x3;
rail->rail = nvbios_rd08(bios, entry + 0x4);
break; break;
case 0x20: case 0x20:
rail->mode = nvbios_rd08(bios, entry); rail->mode = nvbios_rd08(bios, entry);
rail->extdev_id = nvbios_rd08(bios, entry + 0x1); rail->extdev_id = nvbios_rd08(bios, entry + 0x1);
rail->resistor_mohm = nvbios_rd08(bios, entry + 0x5); res_start = 0x5;
rail->rail = nvbios_rd08(bios, entry + 0x6); 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; 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; return 0;
......
...@@ -61,7 +61,17 @@ nvbios_vmap_parse(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, ...@@ -61,7 +61,17 @@ nvbios_vmap_parse(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
memset(info, 0x00, sizeof(*info)); memset(info, 0x00, sizeof(*info));
switch (!!vmap * *ver) { switch (!!vmap * *ver) {
case 0x10: case 0x10:
info->max0 = 0xff;
info->max1 = 0xff;
info->max2 = 0xff;
break;
case 0x20: 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; break;
} }
return vmap; return vmap;
...@@ -95,7 +105,7 @@ nvbios_vmap_entry_parse(struct nvkm_bios *bios, int idx, u8 *ver, u8 *len, ...@@ -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); info->arg[2] = nvbios_rd32(bios, vmap + 0x10);
break; break;
case 0x20: case 0x20:
info->unk0 = nvbios_rd08(bios, vmap + 0x00); info->mode = nvbios_rd08(bios, vmap + 0x00);
info->link = nvbios_rd08(bios, vmap + 0x01); info->link = nvbios_rd08(bios, vmap + 0x01);
info->min = nvbios_rd32(bios, vmap + 0x02); info->min = nvbios_rd32(bios, vmap + 0x02);
info->max = nvbios_rd32(bios, vmap + 0x06); 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, ...@@ -75,20 +75,24 @@ nvbios_volt_parse(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
case 0x12: case 0x12:
info->type = NVBIOS_VOLT_GPIO; info->type = NVBIOS_VOLT_GPIO;
info->vidmask = nvbios_rd08(bios, volt + 0x04); info->vidmask = nvbios_rd08(bios, volt + 0x04);
info->ranged = false;
break; break;
case 0x20: case 0x20:
info->type = NVBIOS_VOLT_GPIO; info->type = NVBIOS_VOLT_GPIO;
info->vidmask = nvbios_rd08(bios, volt + 0x05); info->vidmask = nvbios_rd08(bios, volt + 0x05);
info->ranged = false;
break; break;
case 0x30: case 0x30:
info->type = NVBIOS_VOLT_GPIO; info->type = NVBIOS_VOLT_GPIO;
info->vidmask = nvbios_rd08(bios, volt + 0x04); info->vidmask = nvbios_rd08(bios, volt + 0x04);
info->ranged = false;
break; break;
case 0x40: case 0x40:
info->type = NVBIOS_VOLT_GPIO; info->type = NVBIOS_VOLT_GPIO;
info->base = nvbios_rd32(bios, volt + 0x04); info->base = nvbios_rd32(bios, volt + 0x04);
info->step = nvbios_rd16(bios, volt + 0x08); info->step = nvbios_rd16(bios, volt + 0x08);
info->vidmask = nvbios_rd08(bios, volt + 0x0b); info->vidmask = nvbios_rd08(bios, volt + 0x0b);
info->ranged = true; /* XXX: find the flag byte */
/*XXX*/ /*XXX*/
info->min = 0; info->min = 0;
info->max = info->base; info->max = info->base;
...@@ -104,9 +108,11 @@ nvbios_volt_parse(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, ...@@ -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_freq = nvbios_rd32(bios, volt + 0x5) / 1000;
info->pwm_range = nvbios_rd32(bios, volt + 0x16); info->pwm_range = nvbios_rd32(bios, volt + 0x16);
} else { } else {
info->type = NVBIOS_VOLT_GPIO; info->type = NVBIOS_VOLT_GPIO;
info->vidmask = nvbios_rd08(bios, volt + 0x06); info->vidmask = nvbios_rd08(bios, volt + 0x06);
info->step = nvbios_rd16(bios, volt + 0x16); info->step = nvbios_rd16(bios, volt + 0x16);
info->ranged =
!!(nvbios_rd08(bios, volt + 0x4) & 0x2);
} }
break; break;
} }
...@@ -142,7 +148,10 @@ nvbios_volt_entry_parse(struct nvkm_bios *bios, int idx, u8 *ver, u8 *len, ...@@ -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; info->vid = nvbios_rd08(bios, volt + 0x01) >> 2;
break; break;
case 0x40: case 0x40:
break;
case 0x50: case 0x50:
info->voltage = nvbios_rd32(bios, volt) & 0x001fffff;
info->vid = (nvbios_rd32(bios, volt) >> 23) & 0xff;
break; break;
} }
return volt; return volt;
......
/*
* 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 @@ ...@@ -27,6 +27,7 @@
#include <subdev/bios/boost.h> #include <subdev/bios/boost.h>
#include <subdev/bios/cstep.h> #include <subdev/bios/cstep.h>
#include <subdev/bios/perf.h> #include <subdev/bios/perf.h>
#include <subdev/bios/vpstate.h>
#include <subdev/fb.h> #include <subdev/fb.h>
#include <subdev/therm.h> #include <subdev/therm.h>
#include <subdev/volt.h> #include <subdev/volt.h>
...@@ -74,6 +75,88 @@ nvkm_clk_adjust(struct nvkm_clk *clk, bool adjust, ...@@ -74,6 +75,88 @@ nvkm_clk_adjust(struct nvkm_clk *clk, bool adjust,
/****************************************************************************** /******************************************************************************
* C-States * 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 static int
nvkm_cstate_prog(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei) 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) ...@@ -85,7 +168,8 @@ nvkm_cstate_prog(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei)
int ret; int ret;
if (!list_empty(&pstate->list)) { 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 { } else {
cstate = &pstate->base; cstate = &pstate->base;
} }
...@@ -99,7 +183,8 @@ nvkm_cstate_prog(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei) ...@@ -99,7 +183,8 @@ nvkm_cstate_prog(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei)
} }
if (volt) { 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) { if (ret && ret != -ENODEV) {
nvkm_error(subdev, "failed to raise voltage: %d\n", ret); nvkm_error(subdev, "failed to raise voltage: %d\n", ret);
return ret; return ret;
...@@ -113,7 +198,8 @@ nvkm_cstate_prog(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei) ...@@ -113,7 +198,8 @@ nvkm_cstate_prog(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei)
} }
if (volt) { 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) if (ret && ret != -ENODEV)
nvkm_error(subdev, "failed to lower voltage: %d\n", ret); nvkm_error(subdev, "failed to lower voltage: %d\n", ret);
} }
...@@ -138,6 +224,7 @@ static int ...@@ -138,6 +224,7 @@ static int
nvkm_cstate_new(struct nvkm_clk *clk, int idx, struct nvkm_pstate *pstate) nvkm_cstate_new(struct nvkm_clk *clk, int idx, struct nvkm_pstate *pstate)
{ {
struct nvkm_bios *bios = clk->subdev.device->bios; struct nvkm_bios *bios = clk->subdev.device->bios;
struct nvkm_volt *volt = clk->subdev.device->volt;
const struct nvkm_domain *domain = clk->domains; const struct nvkm_domain *domain = clk->domains;
struct nvkm_cstate *cstate = NULL; struct nvkm_cstate *cstate = NULL;
struct nvbios_cstepX cstepX; struct nvbios_cstepX cstepX;
...@@ -148,12 +235,16 @@ nvkm_cstate_new(struct nvkm_clk *clk, int idx, struct nvkm_pstate *pstate) ...@@ -148,12 +235,16 @@ nvkm_cstate_new(struct nvkm_clk *clk, int idx, struct nvkm_pstate *pstate)
if (!data) if (!data)
return -ENOENT; return -ENOENT;
if (volt && nvkm_volt_map_min(volt, cstepX.voltage) > volt->max_uv)
return -EINVAL;
cstate = kzalloc(sizeof(*cstate), GFP_KERNEL); cstate = kzalloc(sizeof(*cstate), GFP_KERNEL);
if (!cstate) if (!cstate)
return -ENOMEM; return -ENOMEM;
*cstate = pstate->base; *cstate = pstate->base;
cstate->voltage = cstepX.voltage; cstate->voltage = cstepX.voltage;
cstate->id = idx;
while (domain && domain->name != nv_clk_src_max) { while (domain && domain->name != nv_clk_src_max) {
if (domain->flags & NVKM_CLK_DOM_FLAG_CORE) { if (domain->flags & NVKM_CLK_DOM_FLAG_CORE) {
...@@ -175,7 +266,7 @@ static int ...@@ -175,7 +266,7 @@ static int
nvkm_pstate_prog(struct nvkm_clk *clk, int pstatei) nvkm_pstate_prog(struct nvkm_clk *clk, int pstatei)
{ {
struct nvkm_subdev *subdev = &clk->subdev; 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_pci *pci = subdev->device->pci;
struct nvkm_pstate *pstate; struct nvkm_pstate *pstate;
int ret, idx = 0; int ret, idx = 0;
...@@ -190,7 +281,8 @@ nvkm_pstate_prog(struct nvkm_clk *clk, int pstatei) ...@@ -190,7 +281,8 @@ nvkm_pstate_prog(struct nvkm_clk *clk, int pstatei)
nvkm_pcie_set_link(pci, pstate->pcie_speed, pstate->pcie_width); 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]; int khz = pstate->base.domain[nv_clk_src_mem];
do { do {
ret = ram->func->calc(ram, khz); ret = ram->func->calc(ram, khz);
...@@ -200,7 +292,7 @@ nvkm_pstate_prog(struct nvkm_clk *clk, int pstatei) ...@@ -200,7 +292,7 @@ nvkm_pstate_prog(struct nvkm_clk *clk, int pstatei)
ram->func->tidy(ram); ram->func->tidy(ram);
} }
return nvkm_cstate_prog(clk, pstate, 0); return nvkm_cstate_prog(clk, pstate, NVKM_CLK_CSTATE_HIGHEST);
} }
static void static void
...@@ -214,14 +306,14 @@ nvkm_pstate_work(struct work_struct *work) ...@@ -214,14 +306,14 @@ nvkm_pstate_work(struct work_struct *work)
return; return;
clk->pwrsrc = power_supply_is_system_supplied(); 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->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; pstate = clk->pwrsrc ? clk->ustate_ac : clk->ustate_dc;
if (clk->state_nr && pstate != -1) { if (clk->state_nr && pstate != -1) {
pstate = (pstate < 0) ? clk->astate : pstate; 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); pstate = max(pstate, clk->dstate);
} else { } else {
pstate = clk->pstate = -1; pstate = clk->pstate = -1;
...@@ -448,13 +540,12 @@ nvkm_clk_astate(struct nvkm_clk *clk, int req, int rel, bool wait) ...@@ -448,13 +540,12 @@ nvkm_clk_astate(struct nvkm_clk *clk, int req, int rel, bool wait)
} }
int 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 (clk->temp == temp)
if ( rel) clk->tstate += rel; return 0;
clk->tstate = min(clk->tstate, 0); clk->temp = temp;
clk->tstate = max(clk->tstate, -(clk->state_nr - 1)); return nvkm_pstate_calc(clk, false);
return nvkm_pstate_calc(clk, true);
} }
int int
...@@ -524,9 +615,9 @@ nvkm_clk_init(struct nvkm_subdev *subdev) ...@@ -524,9 +615,9 @@ nvkm_clk_init(struct nvkm_subdev *subdev)
return clk->func->init(clk); return clk->func->init(clk);
clk->astate = clk->state_nr - 1; clk->astate = clk->state_nr - 1;
clk->tstate = 0;
clk->dstate = 0; clk->dstate = 0;
clk->pstate = -1; clk->pstate = -1;
clk->temp = 90; /* reasonable default value */
nvkm_pstate_calc(clk, true); nvkm_pstate_calc(clk, true);
return 0; return 0;
} }
...@@ -561,10 +652,22 @@ int ...@@ -561,10 +652,22 @@ int
nvkm_clk_ctor(const struct nvkm_clk_func *func, struct nvkm_device *device, nvkm_clk_ctor(const struct nvkm_clk_func *func, struct nvkm_device *device,
int index, bool allow_reclock, struct nvkm_clk *clk) 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; int ret, idx, arglen;
const char *mode; 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; clk->func = func;
INIT_LIST_HEAD(&clk->states); INIT_LIST_HEAD(&clk->states);
clk->domains = func->domains; clk->domains = func->domains;
...@@ -607,6 +710,8 @@ nvkm_clk_ctor(const struct nvkm_clk_func *func, struct nvkm_device *device, ...@@ -607,6 +710,8 @@ nvkm_clk_ctor(const struct nvkm_clk_func *func, struct nvkm_device *device,
if (mode) if (mode)
clk->ustate_dc = nvkm_clk_nstate(clk, mode, arglen); clk->ustate_dc = nvkm_clk_nstate(clk, mode, arglen);
clk->boost_mode = nvkm_longopt(device->cfgopt, "NvBoost",
NVKM_CLK_BOOST_NONE);
return 0; return 0;
} }
......
...@@ -457,7 +457,7 @@ gf100_clk = { ...@@ -457,7 +457,7 @@ gf100_clk = {
{ nv_clk_src_hubk06 , 0x00 }, { nv_clk_src_hubk06 , 0x00 },
{ nv_clk_src_hubk01 , 0x01 }, { nv_clk_src_hubk01 , 0x01 },
{ nv_clk_src_copy , 0x02 }, { 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_rop , 0x04 },
{ nv_clk_src_mem , 0x05, 0, "memory", 1000 }, { nv_clk_src_mem , 0x05, 0, "memory", 1000 },
{ nv_clk_src_vdec , 0x06 }, { nv_clk_src_vdec , 0x06 },
......
...@@ -491,7 +491,7 @@ gk104_clk = { ...@@ -491,7 +491,7 @@ gk104_clk = {
.domains = { .domains = {
{ nv_clk_src_crystal, 0xff }, { nv_clk_src_crystal, 0xff },
{ nv_clk_src_href , 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_hubk07 , 0x01, NVKM_CLK_DOM_FLAG_CORE },
{ nv_clk_src_rop , 0x02, NVKM_CLK_DOM_FLAG_CORE }, { nv_clk_src_rop , 0x02, NVKM_CLK_DOM_FLAG_CORE },
{ nv_clk_src_mem , 0x03, 0, "memory", 500 }, { nv_clk_src_mem , 0x03, 0, "memory", 500 },
......
...@@ -50,24 +50,33 @@ gf100_fb_intr(struct nvkm_fb *base) ...@@ -50,24 +50,33 @@ gf100_fb_intr(struct nvkm_fb *base)
} }
int 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; int ret, size = 0x1000;
size = nvkm_longopt(device->cfgopt, "MmuDebugBufferSize", size); size = nvkm_longopt(device->cfgopt, "MmuDebugBufferSize", size);
size = min(size, 0x1000); size = min(size, 0x1000);
ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, size, 0x1000, ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, size, 0x1000,
false, &fb->mmu_rd); false, &fb->base.mmu_rd);
if (ret) if (ret)
return ret; return ret;
ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, size, 0x1000, ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, size, 0x1000,
false, &fb->mmu_wr); false, &fb->base.mmu_wr);
if (ret) if (ret)
return 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; return 0;
} }
...@@ -123,14 +132,6 @@ gf100_fb_new_(const struct nvkm_fb_func *func, struct nvkm_device *device, ...@@ -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); nvkm_fb_ctor(func, device, index, &fb->base);
*pfb = &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; return 0;
} }
......
...@@ -210,6 +210,23 @@ nv50_fb_intr(struct nvkm_fb *base) ...@@ -210,6 +210,23 @@ nv50_fb_intr(struct nvkm_fb *base)
nvkm_fifo_chan_put(fifo, flags, &chan); 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 static void
nv50_fb_init(struct nvkm_fb *base) nv50_fb_init(struct nvkm_fb *base)
{ {
...@@ -245,6 +262,7 @@ nv50_fb_dtor(struct nvkm_fb *base) ...@@ -245,6 +262,7 @@ nv50_fb_dtor(struct nvkm_fb *base)
static const struct nvkm_fb_func static const struct nvkm_fb_func
nv50_fb_ = { nv50_fb_ = {
.dtor = nv50_fb_dtor, .dtor = nv50_fb_dtor,
.oneinit = nv50_fb_oneinit,
.init = nv50_fb_init, .init = nv50_fb_init,
.intr = nv50_fb_intr, .intr = nv50_fb_intr,
.ram_new = nv50_fb_ram_new, .ram_new = nv50_fb_ram_new,
...@@ -263,16 +281,6 @@ nv50_fb_new_(const struct nv50_fb_func *func, struct nvkm_device *device, ...@@ -263,16 +281,6 @@ nv50_fb_new_(const struct nv50_fb_func *func, struct nvkm_device *device,
fb->func = func; fb->func = func;
*pfb = &fb->base; *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; return 0;
} }
......
...@@ -24,6 +24,7 @@ int gf100_ram_ctor(const struct nvkm_ram_func *, struct nvkm_fb *, ...@@ -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 **); int gf100_ram_get(struct nvkm_ram *, u64, u32, u32, u32, struct nvkm_mem **);
void gf100_ram_put(struct nvkm_ram *, 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); int gk104_ram_init(struct nvkm_ram *ram);
/* RAM type-specific MR calculation routines */ /* RAM type-specific MR calculation routines */
......
...@@ -259,7 +259,9 @@ gk104_ram_calc_gddr5(struct gk104_ram *ram, u32 freq) ...@@ -259,7 +259,9 @@ gk104_ram_calc_gddr5(struct gk104_ram *ram, u32 freq)
ram_mask(fuc, 0x10f808, 0x40000000, 0x40000000); ram_mask(fuc, 0x10f808, 0x40000000, 0x40000000);
ram_block(fuc); 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.. */ /* MR1: turn termination on early, for some reason.. */
if ((ram->base.mr[1] & 0x03c) != 0x030) { if ((ram->base.mr[1] & 0x03c) != 0x030) {
...@@ -658,7 +660,9 @@ gk104_ram_calc_gddr5(struct gk104_ram *ram, u32 freq) ...@@ -658,7 +660,9 @@ gk104_ram_calc_gddr5(struct gk104_ram *ram, u32 freq)
gk104_ram_train(fuc, 0x80020000, 0x01000000); gk104_ram_train(fuc, 0x80020000, 0x01000000);
ram_unblock(fuc); 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) if (next->bios.rammap_11_08_01)
data = 0x00000800; data = 0x00000800;
...@@ -706,7 +710,9 @@ gk104_ram_calc_sddr3(struct gk104_ram *ram, u32 freq) ...@@ -706,7 +710,9 @@ gk104_ram_calc_sddr3(struct gk104_ram *ram, u32 freq)
ram_mask(fuc, 0x10f808, 0x40000000, 0x40000000); ram_mask(fuc, 0x10f808, 0x40000000, 0x40000000);
ram_block(fuc); 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)) { if (vc == 1 && ram_have(fuc, gpio2E)) {
u32 temp = ram_mask(fuc, gpio2E, 0x3000, fuc->r_func2E[1]); 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) ...@@ -936,7 +942,9 @@ gk104_ram_calc_sddr3(struct gk104_ram *ram, u32 freq)
ram_nsec(fuc, 1000); ram_nsec(fuc, 1000);
ram_unblock(fuc); 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) if (next->bios.rammap_11_08_01)
data = 0x00000800; data = 0x00000800;
...@@ -1529,6 +1537,12 @@ gk104_ram_func = { ...@@ -1529,6 +1537,12 @@ gk104_ram_func = {
int int
gk104_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram) 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_subdev *subdev = &fb->subdev;
struct nvkm_device *device = subdev->device; struct nvkm_device *device = subdev->device;
...@@ -1544,7 +1558,7 @@ gk104_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram) ...@@ -1544,7 +1558,7 @@ gk104_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram)
return -ENOMEM; return -ENOMEM;
*pram = &ram->base; *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) if (ret)
return ret; return ret;
......
...@@ -23,18 +23,8 @@ ...@@ -23,18 +23,8 @@
*/ */
#include "ram.h" #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 int
gm107_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram) gm107_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram)
{ {
if (!(*pram = kzalloc(sizeof(**pram), GFP_KERNEL))) return gk104_ram_ctor(fb, pram, 0x021c14);
return -ENOMEM;
return gf100_ram_ctor(&gm107_ram_func, fb, 0x021c14, *pram);
} }
...@@ -29,7 +29,7 @@ gk20a_ibus_init_ibus_ring(struct nvkm_subdev *ibus) ...@@ -29,7 +29,7 @@ gk20a_ibus_init_ibus_ring(struct nvkm_subdev *ibus)
nvkm_mask(device, 0x137250, 0x3f, 0); nvkm_mask(device, 0x137250, 0x3f, 0);
nvkm_mask(device, 0x000200, 0x20, 0); nvkm_mask(device, 0x000200, 0x20, 0);
usleep_range(20, 30); udelay(20);
nvkm_mask(device, 0x000200, 0x20, 0x20); nvkm_mask(device, 0x000200, 0x20, 0x20);
nvkm_wr32(device, 0x12004c, 0x4); nvkm_wr32(device, 0x12004c, 0x4);
......
...@@ -95,61 +95,13 @@ nvkm_iccsense_ina3221_read(struct nvkm_iccsense *iccsense, ...@@ -95,61 +95,13 @@ nvkm_iccsense_ina3221_read(struct nvkm_iccsense *iccsense,
40 * 8); 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 static void
nvkm_iccsense_sensor_config(struct nvkm_iccsense *iccsense, nvkm_iccsense_sensor_config(struct nvkm_iccsense *iccsense,
struct nvkm_iccsense_sensor *sensor) struct nvkm_iccsense_sensor *sensor)
{ {
switch (sensor->type) { struct nvkm_subdev *subdev = &iccsense->subdev;
case NVBIOS_EXTDEV_INA209: nvkm_trace(subdev, "write config of extdev %i: 0x%04x\n", sensor->id, sensor->config);
case NVBIOS_EXTDEV_INA219: nv_wr16i2cr(sensor->i2c, sensor->addr, 0x00, sensor->config);
nvkm_iccsense_ina209_config(iccsense, sensor);
break;
case NVBIOS_EXTDEV_INA3221:
nvkm_iccsense_ina3221_config(iccsense, sensor);
break;
default:
break;
}
} }
int int
...@@ -196,7 +148,6 @@ nvkm_iccsense_dtor(struct nvkm_subdev *subdev) ...@@ -196,7 +148,6 @@ nvkm_iccsense_dtor(struct nvkm_subdev *subdev)
static struct nvkm_iccsense_sensor* static struct nvkm_iccsense_sensor*
nvkm_iccsense_create_sensor(struct nvkm_iccsense *iccsense, u8 id) nvkm_iccsense_create_sensor(struct nvkm_iccsense *iccsense, u8 id)
{ {
struct nvkm_subdev *subdev = &iccsense->subdev; struct nvkm_subdev *subdev = &iccsense->subdev;
struct nvkm_bios *bios = subdev->device->bios; struct nvkm_bios *bios = subdev->device->bios;
struct nvkm_i2c *i2c = subdev->device->i2c; struct nvkm_i2c *i2c = subdev->device->i2c;
...@@ -245,7 +196,7 @@ nvkm_iccsense_create_sensor(struct nvkm_iccsense *iccsense, u8 id) ...@@ -245,7 +196,7 @@ nvkm_iccsense_create_sensor(struct nvkm_iccsense *iccsense, u8 id)
sensor->type = extdev.type; sensor->type = extdev.type;
sensor->i2c = &i2c_bus->i2c; sensor->i2c = &i2c_bus->i2c;
sensor->addr = addr; sensor->addr = addr;
sensor->rail_mask = 0x0; sensor->config = 0x0;
return sensor; return sensor;
} }
...@@ -273,48 +224,56 @@ nvkm_iccsense_oneinit(struct nvkm_subdev *subdev) ...@@ -273,48 +224,56 @@ nvkm_iccsense_oneinit(struct nvkm_subdev *subdev)
iccsense->data_valid = true; iccsense->data_valid = true;
for (i = 0; i < stbl.nr_entry; ++i) { for (i = 0; i < stbl.nr_entry; ++i) {
struct pwr_rail_t *r = &stbl.rail[i]; struct pwr_rail_t *pwr_rail = &stbl.rail[i];
struct nvkm_iccsense_rail *rail;
struct nvkm_iccsense_sensor *sensor; struct nvkm_iccsense_sensor *sensor;
int (*read)(struct nvkm_iccsense *, int r;
struct nvkm_iccsense_rail *);
if (!r->mode || r->resistor_mohm == 0) if (pwr_rail->mode != 1 || !pwr_rail->resistor_count)
continue; continue;
sensor = nvkm_iccsense_get_sensor(iccsense, r->extdev_id); sensor = nvkm_iccsense_get_sensor(iccsense, pwr_rail->extdev_id);
if (!sensor) if (!sensor)
continue; continue;
switch (sensor->type) { if (!sensor->config)
case NVBIOS_EXTDEV_INA209: sensor->config = pwr_rail->config;
if (r->rail != 0) else if (sensor->config != pwr_rail->config)
continue; nvkm_error(subdev, "config mismatch found for extdev %i\n", pwr_rail->extdev_id);
read = nvkm_iccsense_ina209_read;
break; for (r = 0; r < pwr_rail->resistor_count; ++r) {
case NVBIOS_EXTDEV_INA219: struct nvkm_iccsense_rail *rail;
if (r->rail != 0) 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; continue;
read = nvkm_iccsense_ina219_read;
break; switch (sensor->type) {
case NVBIOS_EXTDEV_INA3221: case NVBIOS_EXTDEV_INA209:
if (r->rail >= 3) 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; continue;
read = nvkm_iccsense_ina3221_read; }
break;
default: rail = kmalloc(sizeof(*rail), GFP_KERNEL);
continue; 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);
} }
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);
} }
return 0; return 0;
} }
......
...@@ -10,7 +10,7 @@ struct nvkm_iccsense_sensor { ...@@ -10,7 +10,7 @@ struct nvkm_iccsense_sensor {
enum nvbios_extdev_type type; enum nvbios_extdev_type type;
struct i2c_adapter *i2c; struct i2c_adapter *i2c;
u8 addr; u8 addr;
u8 rail_mask; u16 config;
}; };
struct nvkm_iccsense_rail { struct nvkm_iccsense_rail {
......
...@@ -23,8 +23,8 @@ ...@@ -23,8 +23,8 @@
*/ */
#include "mxms.h" #include "mxms.h"
#define ROM16(x) le16_to_cpu(*(u16 *)&(x)) #define ROM16(x) get_unaligned_le16(&(x))
#define ROM32(x) le32_to_cpu(*(u32 *)&(x)) #define ROM32(x) get_unaligned_le32(&(x))
static u8 * static u8 *
mxms_data(struct nvkm_mxm *mxm) mxms_data(struct nvkm_mxm *mxm)
......
nvkm-y += nvkm/subdev/volt/base.o nvkm-y += nvkm/subdev/volt/base.o
nvkm-y += nvkm/subdev/volt/gpio.o nvkm-y += nvkm/subdev/volt/gpio.o
nvkm-y += nvkm/subdev/volt/nv40.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/gk104.o
nvkm-y += nvkm/subdev/volt/gk20a.o nvkm-y += nvkm/subdev/volt/gk20a.o
nvkm-y += nvkm/subdev/volt/gm20b.o nvkm-y += nvkm/subdev/volt/gm20b.o
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <subdev/bios.h> #include <subdev/bios.h>
#include <subdev/bios/vmap.h> #include <subdev/bios/vmap.h>
#include <subdev/bios/volt.h> #include <subdev/bios/volt.h>
#include <subdev/therm.h>
int int
nvkm_volt_get(struct nvkm_volt *volt) nvkm_volt_get(struct nvkm_volt *volt)
...@@ -50,23 +51,35 @@ static int ...@@ -50,23 +51,35 @@ static int
nvkm_volt_set(struct nvkm_volt *volt, u32 uv) nvkm_volt_set(struct nvkm_volt *volt, u32 uv)
{ {
struct nvkm_subdev *subdev = &volt->subdev; 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) if (volt->func->volt_set)
return volt->func->volt_set(volt, uv); return volt->func->volt_set(volt, uv);
for (i = 0; i < volt->vid_nr; i++) { for (i = 0; i < volt->vid_nr; i++) {
if (volt->vid[i].uv == uv) { int err = volt->vid[i].uv - uv;
ret = volt->func->vid_set(volt, volt->vid[i].vid); if (err < 0 || err > best_err)
nvkm_debug(subdev, "set %duv: %d\n", uv, ret); continue;
best_err = err;
best = i;
if (best_err == 0)
break; 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; return ret;
} }
static int int
nvkm_volt_map(struct nvkm_volt *volt, u8 id) nvkm_volt_map_min(struct nvkm_volt *volt, u8 id)
{ {
struct nvkm_bios *bios = volt->subdev.device->bios; struct nvkm_bios *bios = volt->subdev.device->bios;
struct nvbios_vmap_entry info; struct nvbios_vmap_entry info;
...@@ -76,7 +89,7 @@ nvkm_volt_map(struct nvkm_volt *volt, u8 id) ...@@ -76,7 +89,7 @@ nvkm_volt_map(struct nvkm_volt *volt, u8 id)
vmap = nvbios_vmap_entry_parse(bios, id, &ver, &len, &info); vmap = nvbios_vmap_entry_parse(bios, id, &ver, &len, &info);
if (vmap) { if (vmap) {
if (info.link != 0xff) { if (info.link != 0xff) {
int ret = nvkm_volt_map(volt, info.link); int ret = nvkm_volt_map_min(volt, info.link);
if (ret < 0) if (ret < 0)
return ret; return ret;
info.min += ret; info.min += ret;
...@@ -88,19 +101,79 @@ nvkm_volt_map(struct nvkm_volt *volt, u8 id) ...@@ -88,19 +101,79 @@ nvkm_volt_map(struct nvkm_volt *volt, u8 id)
} }
int 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; int ret;
if (volt->func->set_id) if (volt->func->set_id)
return volt->func->set_id(volt, id, condition); return volt->func->set_id(volt, id, condition);
ret = nvkm_volt_map(volt, id); ret = nvkm_volt_map(volt, id, temp);
if (ret >= 0) { if (ret >= 0) {
int prev = nvkm_volt_get(volt); int prev = nvkm_volt_get(volt);
if (!condition || prev < 0 || if (!condition || prev < 0 ||
(condition < 0 && ret < prev) || (condition < 0 && ret < prev) ||
(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); ret = nvkm_volt_set(volt, ret);
} else { } else {
ret = 0; ret = 0;
...@@ -112,6 +185,7 @@ nvkm_volt_set_id(struct nvkm_volt *volt, u8 id, int condition) ...@@ -112,6 +185,7 @@ nvkm_volt_set_id(struct nvkm_volt *volt, u8 id, int condition)
static void static void
nvkm_volt_parse_bios(struct nvkm_bios *bios, struct nvkm_volt *volt) 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_entry ivid;
struct nvbios_volt info; struct nvbios_volt info;
u8 ver, hdr, cnt, len; u8 ver, hdr, cnt, len;
...@@ -119,7 +193,8 @@ nvkm_volt_parse_bios(struct nvkm_bios *bios, struct nvkm_volt *volt) ...@@ -119,7 +193,8 @@ nvkm_volt_parse_bios(struct nvkm_bios *bios, struct nvkm_volt *volt)
int i; int i;
data = nvbios_volt_parse(bios, &ver, &hdr, &cnt, &len, &info); 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->min_uv = info.min;
volt->max_uv = info.max; volt->max_uv = info.max;
for (i = 0; i < info.vidmask + 1; i++) { for (i = 0; i < info.vidmask + 1; i++) {
...@@ -132,7 +207,8 @@ nvkm_volt_parse_bios(struct nvkm_bios *bios, struct nvkm_volt *volt) ...@@ -132,7 +207,8 @@ nvkm_volt_parse_bios(struct nvkm_bios *bios, struct nvkm_volt *volt)
info.base += info.step; info.base += info.step;
} }
volt->vid_mask = info.vidmask; 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->min_uv = 0xffffffff;
volt->max_uv = 0; volt->max_uv = 0;
for (i = 0; i < cnt; i++) { for (i = 0; i < cnt; i++) {
...@@ -153,6 +229,14 @@ nvkm_volt_parse_bios(struct nvkm_bios *bios, struct nvkm_volt *volt) ...@@ -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 static int
nvkm_volt_init(struct nvkm_subdev *subdev) nvkm_volt_init(struct nvkm_subdev *subdev)
{ {
...@@ -167,6 +251,21 @@ nvkm_volt_init(struct nvkm_subdev *subdev) ...@@ -167,6 +251,21 @@ nvkm_volt_init(struct nvkm_subdev *subdev)
return 0; 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 * static void *
nvkm_volt_dtor(struct nvkm_subdev *subdev) nvkm_volt_dtor(struct nvkm_subdev *subdev)
{ {
...@@ -177,6 +276,7 @@ static const struct nvkm_subdev_func ...@@ -177,6 +276,7 @@ static const struct nvkm_subdev_func
nvkm_volt = { nvkm_volt = {
.dtor = nvkm_volt_dtor, .dtor = nvkm_volt_dtor,
.init = nvkm_volt_init, .init = nvkm_volt_init,
.oneinit = nvkm_volt_oneinit,
}; };
void void
...@@ -191,9 +291,22 @@ nvkm_volt_ctor(const struct nvkm_volt_func *func, struct nvkm_device *device, ...@@ -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 */ /* Assuming the non-bios device should build the voltage table later */
if (bios) { if (bios) {
u8 ver, hdr, cnt, len;
struct nvbios_vmap vmap;
nvkm_volt_parse_bios(bios, volt); nvkm_volt_parse_bios(bios, volt);
nvkm_debug(&volt->subdev, "min: %iuv max: %iuv\n", nvkm_debug(&volt->subdev, "min: %iuv max: %iuv\n",
volt->min_uv, volt->max_uv); 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) { if (volt->vid_nr) {
......
/*
* 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 @@ ...@@ -27,6 +27,7 @@
#include <subdev/gpio.h> #include <subdev/gpio.h>
#include <subdev/bios.h> #include <subdev/bios.h>
#include <subdev/bios/volt.h> #include <subdev/bios/volt.h>
#include <subdev/fuse.h>
#define gk104_volt(p) container_of((p), struct gk104_volt, base) #define gk104_volt(p) container_of((p), struct gk104_volt, base)
struct gk104_volt { struct gk104_volt {
...@@ -64,13 +65,33 @@ gk104_volt_set(struct nvkm_volt *base, u32 uv) ...@@ -64,13 +65,33 @@ gk104_volt_set(struct nvkm_volt *base, u32 uv)
return 0; 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 static const struct nvkm_volt_func
gk104_volt_pwm = { gk104_volt_pwm = {
.oneinit = gf100_volt_oneinit,
.volt_get = gk104_volt_get, .volt_get = gk104_volt_get,
.volt_set = gk104_volt_set, .volt_set = gk104_volt_set,
.speedo_read = gk104_volt_speedo_read,
}, gk104_volt_gpio = { }, gk104_volt_gpio = {
.oneinit = gf100_volt_oneinit,
.vid_get = nvkm_voltgpio_get, .vid_get = nvkm_voltgpio_get,
.vid_set = nvkm_voltgpio_set, .vid_set = nvkm_voltgpio_set,
.speedo_read = gk104_volt_speedo_read,
}; };
int int
......
...@@ -9,11 +9,13 @@ int nvkm_volt_new_(const struct nvkm_volt_func *, struct nvkm_device *, ...@@ -9,11 +9,13 @@ int nvkm_volt_new_(const struct nvkm_volt_func *, struct nvkm_device *,
int index, struct nvkm_volt **); int index, struct nvkm_volt **);
struct nvkm_volt_func { struct nvkm_volt_func {
int (*oneinit)(struct nvkm_volt *);
int (*volt_get)(struct nvkm_volt *); int (*volt_get)(struct nvkm_volt *);
int (*volt_set)(struct nvkm_volt *, u32 uv); int (*volt_set)(struct nvkm_volt *, u32 uv);
int (*vid_get)(struct nvkm_volt *); int (*vid_get)(struct nvkm_volt *);
int (*vid_set)(struct nvkm_volt *, u8 vid); int (*vid_set)(struct nvkm_volt *, u8 vid);
int (*set_id)(struct nvkm_volt *, u8 id, int condition); int (*set_id)(struct nvkm_volt *, u8 id, int condition);
int (*speedo_read)(struct nvkm_volt *);
}; };
int nvkm_voltgpio_init(struct nvkm_volt *); int nvkm_voltgpio_init(struct nvkm_volt *);
...@@ -23,4 +25,6 @@ int nvkm_voltgpio_set(struct nvkm_volt *, u8); ...@@ -23,4 +25,6 @@ int nvkm_voltgpio_set(struct nvkm_volt *, u8);
int nvkm_voltpwm_init(struct nvkm_volt *volt); int nvkm_voltpwm_init(struct nvkm_volt *volt);
int nvkm_voltpwm_get(struct nvkm_volt *volt); int nvkm_voltpwm_get(struct nvkm_volt *volt);
int nvkm_voltpwm_set(struct nvkm_volt *volt, u32 uv); int nvkm_voltpwm_set(struct nvkm_volt *volt, u32 uv);
int gf100_volt_oneinit(struct nvkm_volt *);
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment