aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2016-10-28 00:24:56 -0400
committerDave Airlie <airlied@redhat.com>2016-10-28 00:24:56 -0400
commitfb422950c6cd726fd36eb72a7cf84583440a18a2 (patch)
tree2ff57cfe130961f50aa855bd7d04a23f20b567f0
parent220196b38483be6d84a295d318d48595f65da443 (diff)
parent2ecf7c43d78093a24aa44c0a14a335457f065bb2 (diff)
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 ...
-rw-r--r--drivers/gpu/drm/nouveau/Kbuild1
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/gpio.h1
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/iccsense.h10
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/vmap.h5
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/volt.h5
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/vpstate.h24
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/clk.h18
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h18
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_backlight.c1
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bios.h6
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drm.c7
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.h3
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_led.c139
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_led.h57
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/core/firmware.c1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/device/base.c17
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c37
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c8
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/Kbuild1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/iccsense.c33
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/vmap.c12
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/volt.c15
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/vpstate.c82
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c139
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c25
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c28
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.h1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c24
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgm107.c12
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk20a.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/iccsense/base.c129
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/iccsense/priv.h2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mxm/mxms.c4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/volt/Kbuild1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c137
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/volt/gf100.c70
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk104.c21
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/volt/priv.h4
44 files changed, 904 insertions, 207 deletions
diff --git a/drivers/gpu/drm/nouveau/Kbuild b/drivers/gpu/drm/nouveau/Kbuild
index 2527bf4ca5d9..fde6e3656636 100644
--- a/drivers/gpu/drm/nouveau/Kbuild
+++ b/drivers/gpu/drm/nouveau/Kbuild
@@ -22,6 +22,7 @@ nouveau-$(CONFIG_DEBUG_FS) += nouveau_debugfs.o
22nouveau-y += nouveau_drm.o 22nouveau-y += nouveau_drm.o
23nouveau-y += nouveau_hwmon.o 23nouveau-y += nouveau_hwmon.o
24nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o 24nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o
25nouveau-$(CONFIG_LEDS_CLASS) += nouveau_led.o
25nouveau-y += nouveau_nvif.o 26nouveau-y += nouveau_nvif.o
26nouveau-$(CONFIG_NOUVEAU_PLATFORM_DRIVER) += nouveau_platform.o 27nouveau-$(CONFIG_NOUVEAU_PLATFORM_DRIVER) += nouveau_platform.o
27nouveau-y += nouveau_usif.o # userspace <-> nvif 28nouveau-y += nouveau_usif.o # userspace <-> nvif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/gpio.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/gpio.h
index a47d46dda704..b7a54e605469 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/gpio.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/gpio.h
@@ -6,6 +6,7 @@ enum dcb_gpio_func_name {
6 DCB_GPIO_TVDAC1 = 0x2d, 6 DCB_GPIO_TVDAC1 = 0x2d,
7 DCB_GPIO_FAN = 0x09, 7 DCB_GPIO_FAN = 0x09,
8 DCB_GPIO_FAN_SENSE = 0x3d, 8 DCB_GPIO_FAN_SENSE = 0x3d,
9 DCB_GPIO_LOGO_LED_PWM = 0x84,
9 DCB_GPIO_UNUSED = 0xff, 10 DCB_GPIO_UNUSED = 0xff,
10 DCB_GPIO_VID0 = 0x04, 11 DCB_GPIO_VID0 = 0x04,
11 DCB_GPIO_VID1 = 0x05, 12 DCB_GPIO_VID1 = 0x05,
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/iccsense.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/iccsense.h
index 9cb97477248b..e933d3eede70 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/iccsense.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/iccsense.h
@@ -1,10 +1,16 @@
1#ifndef __NVBIOS_ICCSENSE_H__ 1#ifndef __NVBIOS_ICCSENSE_H__
2#define __NVBIOS_ICCSENSE_H__ 2#define __NVBIOS_ICCSENSE_H__
3struct pwr_rail_resistor_t {
4 u8 mohm;
5 bool enabled;
6};
7
3struct pwr_rail_t { 8struct pwr_rail_t {
4 u8 mode; 9 u8 mode;
5 u8 extdev_id; 10 u8 extdev_id;
6 u8 resistor_mohm; 11 u8 resistor_count;
7 u8 rail; 12 struct pwr_rail_resistor_t resistors[3];
13 u16 config;
8}; 14};
9 15
10struct nvbios_iccsense { 16struct nvbios_iccsense {
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/vmap.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/vmap.h
index 6633c6db9281..8fa1294c27b7 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/vmap.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/vmap.h
@@ -1,6 +1,9 @@
1#ifndef __NVBIOS_VMAP_H__ 1#ifndef __NVBIOS_VMAP_H__
2#define __NVBIOS_VMAP_H__ 2#define __NVBIOS_VMAP_H__
3struct nvbios_vmap { 3struct nvbios_vmap {
4 u8 max0;
5 u8 max1;
6 u8 max2;
4}; 7};
5 8
6u16 nvbios_vmap_table(struct nvkm_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len); 9u16 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 struct nvbios_vmap *); 11 struct nvbios_vmap *);
9 12
10struct nvbios_vmap_entry { 13struct nvbios_vmap_entry {
11 u8 unk0; 14 u8 mode;
12 u8 link; 15 u8 link;
13 u32 min; 16 u32 min;
14 u32 max; 17 u32 max;
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/volt.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/volt.h
index b0df610cec2b..23f3d1b93ebb 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/volt.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/volt.h
@@ -13,8 +13,9 @@ struct nvbios_volt {
13 u32 base; 13 u32 base;
14 14
15 /* GPIO mode */ 15 /* GPIO mode */
16 u8 vidmask; 16 bool ranged;
17 s16 step; 17 u8 vidmask;
18 s16 step;
18 19
19 /* PWM mode */ 20 /* PWM mode */
20 u32 pwm_freq; 21 u32 pwm_freq;
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/vpstate.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/vpstate.h
new file mode 100644
index 000000000000..87f804fc3a88
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/vpstate.h
@@ -0,0 +1,24 @@
1#ifndef __NVBIOS_VPSTATE_H__
2#define __NVBIOS_VPSTATE_H__
3struct nvbios_vpstate_header {
4 u32 offset;
5
6 u8 version;
7 u8 hlen;
8 u8 ecount;
9 u8 elen;
10 u8 scount;
11 u8 slen;
12
13 u8 base_id;
14 u8 boost_id;
15 u8 tdp_id;
16};
17struct nvbios_vpstate_entry {
18 u8 pstate;
19 u16 clock_mhz;
20};
21int nvbios_vpstate_parse(struct nvkm_bios *, struct nvbios_vpstate_header *);
22int nvbios_vpstate_entry(struct nvkm_bios *, struct nvbios_vpstate_header *,
23 u8 idx, struct nvbios_vpstate_entry *);
24#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/clk.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/clk.h
index fb54417bc458..e5275f742977 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/clk.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/clk.h
@@ -6,6 +6,10 @@
6struct nvbios_pll; 6struct nvbios_pll;
7struct nvkm_pll_vals; 7struct nvkm_pll_vals;
8 8
9#define NVKM_CLK_CSTATE_DEFAULT -1 /* POSTed default */
10#define NVKM_CLK_CSTATE_BASE -2 /* pstate base */
11#define NVKM_CLK_CSTATE_HIGHEST -3 /* highest possible */
12
9enum nv_clk_src { 13enum nv_clk_src {
10 nv_clk_src_crystal, 14 nv_clk_src_crystal,
11 nv_clk_src_href, 15 nv_clk_src_href,
@@ -52,6 +56,7 @@ struct nvkm_cstate {
52 struct list_head head; 56 struct list_head head;
53 u8 voltage; 57 u8 voltage;
54 u32 domain[nv_clk_src_max]; 58 u32 domain[nv_clk_src_max];
59 u8 id;
55}; 60};
56 61
57struct nvkm_pstate { 62struct nvkm_pstate {
@@ -67,7 +72,8 @@ struct nvkm_pstate {
67struct nvkm_domain { 72struct nvkm_domain {
68 enum nv_clk_src name; 73 enum nv_clk_src name;
69 u8 bios; /* 0xff for none */ 74 u8 bios; /* 0xff for none */
70#define NVKM_CLK_DOM_FLAG_CORE 0x01 75#define NVKM_CLK_DOM_FLAG_CORE 0x01
76#define NVKM_CLK_DOM_FLAG_VPSTATE 0x02
71 u8 flags; 77 u8 flags;
72 const char *mname; 78 const char *mname;
73 int mdiv; 79 int mdiv;
@@ -93,10 +99,16 @@ struct nvkm_clk {
93 int ustate_ac; /* user-requested (-1 disabled, -2 perfmon) */ 99 int ustate_ac; /* user-requested (-1 disabled, -2 perfmon) */
94 int ustate_dc; /* user-requested (-1 disabled, -2 perfmon) */ 100 int ustate_dc; /* user-requested (-1 disabled, -2 perfmon) */
95 int astate; /* perfmon adjustment (base) */ 101 int astate; /* perfmon adjustment (base) */
96 int tstate; /* thermal adjustment (max-) */
97 int dstate; /* display adjustment (min+) */ 102 int dstate; /* display adjustment (min+) */
103 u8 temp;
98 104
99 bool allow_reclock; 105 bool allow_reclock;
106#define NVKM_CLK_BOOST_NONE 0x0
107#define NVKM_CLK_BOOST_BIOS 0x1
108#define NVKM_CLK_BOOST_FULL 0x2
109 u8 boost_mode;
110 u32 base_khz;
111 u32 boost_khz;
100 112
101 /*XXX: die, these are here *only* to support the completely 113 /*XXX: die, these are here *only* to support the completely
102 * bat-shit insane what-was-nouveau_hw.c code 114 * bat-shit insane what-was-nouveau_hw.c code
@@ -110,7 +122,7 @@ int nvkm_clk_read(struct nvkm_clk *, enum nv_clk_src);
110int nvkm_clk_ustate(struct nvkm_clk *, int req, int pwr); 122int nvkm_clk_ustate(struct nvkm_clk *, int req, int pwr);
111int nvkm_clk_astate(struct nvkm_clk *, int req, int rel, bool wait); 123int nvkm_clk_astate(struct nvkm_clk *, int req, int rel, bool wait);
112int nvkm_clk_dstate(struct nvkm_clk *, int req, int rel); 124int nvkm_clk_dstate(struct nvkm_clk *, int req, int rel);
113int nvkm_clk_tstate(struct nvkm_clk *, int req, int rel); 125int nvkm_clk_tstate(struct nvkm_clk *, u8 temperature);
114 126
115int nv04_clk_new(struct nvkm_device *, int, struct nvkm_clk **); 127int nv04_clk_new(struct nvkm_device *, int, struct nvkm_clk **);
116int nv40_clk_new(struct nvkm_device *, int, struct nvkm_clk **); 128int nv40_clk_new(struct nvkm_device *, int, struct nvkm_clk **);
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h
index b765f4ffcde6..08ef9983c643 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h
@@ -15,12 +15,28 @@ struct nvkm_volt {
15 15
16 u32 max_uv; 16 u32 max_uv;
17 u32 min_uv; 17 u32 min_uv;
18
19 /*
20 * These are fully functional map entries creating a sw ceiling for
21 * the voltage. These all can describe different kind of curves, so
22 * that for any given temperature a different one can return the lowest
23 * value of all three.
24 */
25 u8 max0_id;
26 u8 max1_id;
27 u8 max2_id;
28
29 int speedo;
18}; 30};
19 31
32int nvkm_volt_map(struct nvkm_volt *volt, u8 id, u8 temperature);
33int nvkm_volt_map_min(struct nvkm_volt *volt, u8 id);
20int nvkm_volt_get(struct nvkm_volt *); 34int nvkm_volt_get(struct nvkm_volt *);
21int nvkm_volt_set_id(struct nvkm_volt *, u8 id, int condition); 35int nvkm_volt_set_id(struct nvkm_volt *, u8 id, u8 min_id, u8 temp,
36 int condition);
22 37
23int nv40_volt_new(struct nvkm_device *, int, struct nvkm_volt **); 38int nv40_volt_new(struct nvkm_device *, int, struct nvkm_volt **);
39int gf100_volt_new(struct nvkm_device *, int, struct nvkm_volt **);
24int gk104_volt_new(struct nvkm_device *, int, struct nvkm_volt **); 40int gk104_volt_new(struct nvkm_device *, int, struct nvkm_volt **);
25int gk20a_volt_new(struct nvkm_device *, int, struct nvkm_volt **); 41int gk20a_volt_new(struct nvkm_device *, int, struct nvkm_volt **);
26int gm20b_volt_new(struct nvkm_device *, int, struct nvkm_volt **); 42int gm20b_volt_new(struct nvkm_device *, int, struct nvkm_volt **);
diff --git a/drivers/gpu/drm/nouveau/nouveau_backlight.c b/drivers/gpu/drm/nouveau/nouveau_backlight.c
index f5101be806cb..5e2c5685b4dd 100644
--- a/drivers/gpu/drm/nouveau/nouveau_backlight.c
+++ b/drivers/gpu/drm/nouveau/nouveau_backlight.c
@@ -232,6 +232,7 @@ nouveau_backlight_init(struct drm_device *dev)
232 case NV_DEVICE_INFO_V0_TESLA: 232 case NV_DEVICE_INFO_V0_TESLA:
233 case NV_DEVICE_INFO_V0_FERMI: 233 case NV_DEVICE_INFO_V0_FERMI:
234 case NV_DEVICE_INFO_V0_KEPLER: 234 case NV_DEVICE_INFO_V0_KEPLER:
235 case NV_DEVICE_INFO_V0_MAXWELL:
235 return nv50_backlight_init(connector); 236 return nv50_backlight_init(connector);
236 default: 237 default:
237 break; 238 break;
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.h b/drivers/gpu/drm/nouveau/nouveau_bios.h
index 0067586eb015..18eb061ccafb 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bios.h
+++ b/drivers/gpu/drm/nouveau/nouveau_bios.h
@@ -31,10 +31,8 @@
31 31
32#define DCB_LOC_ON_CHIP 0 32#define DCB_LOC_ON_CHIP 0
33 33
34#define ROM16(x) le16_to_cpu(*(u16 *)&(x)) 34#define ROM16(x) get_unaligned_le16(&(x))
35#define ROM32(x) le32_to_cpu(*(u32 *)&(x)) 35#define ROM32(x) get_unaligned_le32(&(x))
36#define ROM48(x) ({ u8 *p = &(x); (u64)ROM16(p[4]) << 32 | ROM32(p[0]); })
37#define ROM64(x) le64_to_cpu(*(u64 *)&(x))
38#define ROMPTR(d,x) ({ \ 36#define ROMPTR(d,x) ({ \
39 struct nouveau_drm *drm = nouveau_drm((d)); \ 37 struct nouveau_drm *drm = nouveau_drm((d)); \
40 ROM16(x) ? &drm->vbios.data[ROM16(x)] : NULL; \ 38 ROM16(x) ? &drm->vbios.data[ROM16(x)] : NULL; \
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c
index 3100fd88a015..6adf94789417 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
@@ -47,6 +47,7 @@
47#include "nouveau_ttm.h" 47#include "nouveau_ttm.h"
48#include "nouveau_gem.h" 48#include "nouveau_gem.h"
49#include "nouveau_vga.h" 49#include "nouveau_vga.h"
50#include "nouveau_led.h"
50#include "nouveau_hwmon.h" 51#include "nouveau_hwmon.h"
51#include "nouveau_acpi.h" 52#include "nouveau_acpi.h"
52#include "nouveau_bios.h" 53#include "nouveau_bios.h"
@@ -475,6 +476,7 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags)
475 nouveau_hwmon_init(dev); 476 nouveau_hwmon_init(dev);
476 nouveau_accel_init(drm); 477 nouveau_accel_init(drm);
477 nouveau_fbcon_init(dev); 478 nouveau_fbcon_init(dev);
479 nouveau_led_init(dev);
478 480
479 if (nouveau_runtime_pm != 0) { 481 if (nouveau_runtime_pm != 0) {
480 pm_runtime_use_autosuspend(dev->dev); 482 pm_runtime_use_autosuspend(dev->dev);
@@ -510,6 +512,7 @@ nouveau_drm_unload(struct drm_device *dev)
510 pm_runtime_forbid(dev->dev); 512 pm_runtime_forbid(dev->dev);
511 } 513 }
512 514
515 nouveau_led_fini(dev);
513 nouveau_fbcon_fini(dev); 516 nouveau_fbcon_fini(dev);
514 nouveau_accel_fini(drm); 517 nouveau_accel_fini(drm);
515 nouveau_hwmon_fini(dev); 518 nouveau_hwmon_fini(dev);
@@ -561,6 +564,8 @@ nouveau_do_suspend(struct drm_device *dev, bool runtime)
561 struct nouveau_cli *cli; 564 struct nouveau_cli *cli;
562 int ret; 565 int ret;
563 566
567 nouveau_led_suspend(dev);
568
564 if (dev->mode_config.num_crtc) { 569 if (dev->mode_config.num_crtc) {
565 NV_INFO(drm, "suspending console...\n"); 570 NV_INFO(drm, "suspending console...\n");
566 nouveau_fbcon_set_suspend(dev, 1); 571 nouveau_fbcon_set_suspend(dev, 1);
@@ -649,6 +654,8 @@ nouveau_do_resume(struct drm_device *dev, bool runtime)
649 nouveau_fbcon_set_suspend(dev, 0); 654 nouveau_fbcon_set_suspend(dev, 0);
650 } 655 }
651 656
657 nouveau_led_resume(dev);
658
652 return 0; 659 return 0;
653} 660}
654 661
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index 822a0212cd48..c0e2b3207503 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -166,6 +166,9 @@ struct nouveau_drm {
166 struct nouveau_hwmon *hwmon; 166 struct nouveau_hwmon *hwmon;
167 struct nouveau_debugfs *debugfs; 167 struct nouveau_debugfs *debugfs;
168 168
169 /* led management */
170 struct nouveau_led *led;
171
169 /* display power reference */ 172 /* display power reference */
170 bool have_disp_power_ref; 173 bool have_disp_power_ref;
171 174
diff --git a/drivers/gpu/drm/nouveau/nouveau_led.c b/drivers/gpu/drm/nouveau/nouveau_led.c
new file mode 100644
index 000000000000..3e2f1b6cd4df
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nouveau_led.c
@@ -0,0 +1,139 @@
1/*
2 * Copyright (C) 2016 Martin Peres
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial
14 * portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
20 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 *
24 */
25
26/*
27 * Authors:
28 * Martin Peres <martin.peres@free.fr>
29 */
30
31#include <linux/leds.h>
32
33#include "nouveau_led.h"
34#include <nvkm/subdev/gpio.h>
35
36static enum led_brightness
37nouveau_led_get_brightness(struct led_classdev *led)
38{
39 struct drm_device *drm_dev = container_of(led, struct nouveau_led, led)->dev;
40 struct nouveau_drm *drm = nouveau_drm(drm_dev);
41 struct nvif_object *device = &drm->device.object;
42 u32 div, duty;
43
44 div = nvif_rd32(device, 0x61c880) & 0x00ffffff;
45 duty = nvif_rd32(device, 0x61c884) & 0x00ffffff;
46
47 if (div > 0)
48 return duty * LED_FULL / div;
49 else
50 return 0;
51}
52
53static void
54nouveau_led_set_brightness(struct led_classdev *led, enum led_brightness value)
55{
56 struct drm_device *drm_dev = container_of(led, struct nouveau_led, led)->dev;
57 struct nouveau_drm *drm = nouveau_drm(drm_dev);
58 struct nvif_object *device = &drm->device.object;
59
60 u32 input_clk = 27e6; /* PDISPLAY.SOR[1].PWM is connected to the crystal */
61 u32 freq = 100; /* this is what nvidia uses and it should be good-enough */
62 u32 div, duty;
63
64 div = input_clk / freq;
65 duty = value * div / LED_FULL;
66
67 /* for now, this is safe to directly poke those registers because:
68 * - A: nvidia never puts the logo led to any other PWM controler
69 * than PDISPLAY.SOR[1].PWM.
70 * - B: nouveau does not touch these registers anywhere else
71 */
72 nvif_wr32(device, 0x61c880, div);
73 nvif_wr32(device, 0x61c884, 0xc0000000 | duty);
74}
75
76
77int
78nouveau_led_init(struct drm_device *dev)
79{
80 struct nouveau_drm *drm = nouveau_drm(dev);
81 struct nvkm_gpio *gpio = nvxx_gpio(&drm->device);
82 struct dcb_gpio_func logo_led;
83 int ret;
84
85 if (!gpio)
86 return 0;
87
88 /* check that there is a GPIO controlling the logo LED */
89 if (nvkm_gpio_find(gpio, 0, DCB_GPIO_LOGO_LED_PWM, 0xff, &logo_led))
90 return 0;
91
92 drm->led = kzalloc(sizeof(*drm->led), GFP_KERNEL);
93 if (!drm->led)
94 return -ENOMEM;
95 drm->led->dev = dev;
96
97 drm->led->led.name = "nvidia-logo";
98 drm->led->led.max_brightness = 255;
99 drm->led->led.brightness_get = nouveau_led_get_brightness;
100 drm->led->led.brightness_set = nouveau_led_set_brightness;
101
102 ret = led_classdev_register(dev->dev, &drm->led->led);
103 if (ret) {
104 kfree(drm->led);
105 return ret;
106 }
107
108 return 0;
109}
110
111void
112nouveau_led_suspend(struct drm_device *dev)
113{
114 struct nouveau_drm *drm = nouveau_drm(dev);
115
116 if (drm->led)
117 led_classdev_suspend(&drm->led->led);
118}
119
120void
121nouveau_led_resume(struct drm_device *dev)
122{
123 struct nouveau_drm *drm = nouveau_drm(dev);
124
125 if (drm->led)
126 led_classdev_resume(&drm->led->led);
127}
128
129void
130nouveau_led_fini(struct drm_device *dev)
131{
132 struct nouveau_drm *drm = nouveau_drm(dev);
133
134 if (drm->led) {
135 led_classdev_unregister(&drm->led->led);
136 kfree(drm->led);
137 drm->led = NULL;
138 }
139}
diff --git a/drivers/gpu/drm/nouveau/nouveau_led.h b/drivers/gpu/drm/nouveau/nouveau_led.h
new file mode 100644
index 000000000000..187ecdb82002
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nouveau_led.h
@@ -0,0 +1,57 @@
1/*
2 * Copyright 2015 Martin Peres
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Authors: Martin Peres <martin.peres@free.fr>
23 */
24
25#ifndef __NOUVEAU_LED_H__
26#define __NOUVEAU_LED_H__
27
28#include "nouveau_drv.h"
29
30struct led_classdev;
31
32struct nouveau_led {
33 struct drm_device *dev;
34
35 struct led_classdev led;
36};
37
38static inline struct nouveau_led *
39nouveau_led(struct drm_device *dev)
40{
41 return nouveau_drm(dev)->led;
42}
43
44/* nouveau_led.c */
45#if IS_ENABLED(CONFIG_LEDS_CLASS)
46int nouveau_led_init(struct drm_device *dev);
47void nouveau_led_suspend(struct drm_device *dev);
48void nouveau_led_resume(struct drm_device *dev);
49void nouveau_led_fini(struct drm_device *dev);
50#else
51static inline int nouveau_led_init(struct drm_device *dev) { return 0; };
52static inline void nouveau_led_suspend(struct drm_device *dev) { };
53static inline void nouveau_led_resume(struct drm_device *dev) { };
54static inline void nouveau_led_fini(struct drm_device *dev) { };
55#endif
56
57#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/firmware.c b/drivers/gpu/drm/nouveau/nvkm/core/firmware.c
index 34ecd4a7e0c1..058ff46b5f16 100644
--- a/drivers/gpu/drm/nouveau/nvkm/core/firmware.c
+++ b/drivers/gpu/drm/nouveau/nvkm/core/firmware.c
@@ -20,6 +20,7 @@
20 * DEALINGS IN THE SOFTWARE. 20 * DEALINGS IN THE SOFTWARE.
21 */ 21 */
22#include <core/device.h> 22#include <core/device.h>
23#include <core/firmware.h>
23 24
24/** 25/**
25 * nvkm_firmware_get - load firmware from the official nvidia/chip/ directory 26 * nvkm_firmware_get - load firmware from the official nvidia/chip/ directory
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
index 7218a067a6c5..53d171729353 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
@@ -1357,7 +1357,7 @@ nvc0_chipset = {
1357 .pmu = gf100_pmu_new, 1357 .pmu = gf100_pmu_new,
1358 .therm = gt215_therm_new, 1358 .therm = gt215_therm_new,
1359 .timer = nv41_timer_new, 1359 .timer = nv41_timer_new,
1360 .volt = nv40_volt_new, 1360 .volt = gf100_volt_new,
1361 .ce[0] = gf100_ce_new, 1361 .ce[0] = gf100_ce_new,
1362 .ce[1] = gf100_ce_new, 1362 .ce[1] = gf100_ce_new,
1363 .disp = gt215_disp_new, 1363 .disp = gt215_disp_new,
@@ -1394,7 +1394,7 @@ nvc1_chipset = {
1394 .pmu = gf100_pmu_new, 1394 .pmu = gf100_pmu_new,
1395 .therm = gt215_therm_new, 1395 .therm = gt215_therm_new,
1396 .timer = nv41_timer_new, 1396 .timer = nv41_timer_new,
1397 .volt = nv40_volt_new, 1397 .volt = gf100_volt_new,
1398 .ce[0] = gf100_ce_new, 1398 .ce[0] = gf100_ce_new,
1399 .disp = gt215_disp_new, 1399 .disp = gt215_disp_new,
1400 .dma = gf100_dma_new, 1400 .dma = gf100_dma_new,
@@ -1430,7 +1430,7 @@ nvc3_chipset = {
1430 .pmu = gf100_pmu_new, 1430 .pmu = gf100_pmu_new,
1431 .therm = gt215_therm_new, 1431 .therm = gt215_therm_new,
1432 .timer = nv41_timer_new, 1432 .timer = nv41_timer_new,
1433 .volt = nv40_volt_new, 1433 .volt = gf100_volt_new,
1434 .ce[0] = gf100_ce_new, 1434 .ce[0] = gf100_ce_new,
1435 .disp = gt215_disp_new, 1435 .disp = gt215_disp_new,
1436 .dma = gf100_dma_new, 1436 .dma = gf100_dma_new,
@@ -1466,7 +1466,7 @@ nvc4_chipset = {
1466 .pmu = gf100_pmu_new, 1466 .pmu = gf100_pmu_new,
1467 .therm = gt215_therm_new, 1467 .therm = gt215_therm_new,
1468 .timer = nv41_timer_new, 1468 .timer = nv41_timer_new,
1469 .volt = nv40_volt_new, 1469 .volt = gf100_volt_new,
1470 .ce[0] = gf100_ce_new, 1470 .ce[0] = gf100_ce_new,
1471 .ce[1] = gf100_ce_new, 1471 .ce[1] = gf100_ce_new,
1472 .disp = gt215_disp_new, 1472 .disp = gt215_disp_new,
@@ -1503,7 +1503,7 @@ nvc8_chipset = {
1503 .pmu = gf100_pmu_new, 1503 .pmu = gf100_pmu_new,
1504 .therm = gt215_therm_new, 1504 .therm = gt215_therm_new,
1505 .timer = nv41_timer_new, 1505 .timer = nv41_timer_new,
1506 .volt = nv40_volt_new, 1506 .volt = gf100_volt_new,
1507 .ce[0] = gf100_ce_new, 1507 .ce[0] = gf100_ce_new,
1508 .ce[1] = gf100_ce_new, 1508 .ce[1] = gf100_ce_new,
1509 .disp = gt215_disp_new, 1509 .disp = gt215_disp_new,
@@ -1540,7 +1540,7 @@ nvce_chipset = {
1540 .pmu = gf100_pmu_new, 1540 .pmu = gf100_pmu_new,
1541 .therm = gt215_therm_new, 1541 .therm = gt215_therm_new,
1542 .timer = nv41_timer_new, 1542 .timer = nv41_timer_new,
1543 .volt = nv40_volt_new, 1543 .volt = gf100_volt_new,
1544 .ce[0] = gf100_ce_new, 1544 .ce[0] = gf100_ce_new,
1545 .ce[1] = gf100_ce_new, 1545 .ce[1] = gf100_ce_new,
1546 .disp = gt215_disp_new, 1546 .disp = gt215_disp_new,
@@ -1577,7 +1577,7 @@ nvcf_chipset = {
1577 .pmu = gf100_pmu_new, 1577 .pmu = gf100_pmu_new,
1578 .therm = gt215_therm_new, 1578 .therm = gt215_therm_new,
1579 .timer = nv41_timer_new, 1579 .timer = nv41_timer_new,
1580 .volt = nv40_volt_new, 1580 .volt = gf100_volt_new,
1581 .ce[0] = gf100_ce_new, 1581 .ce[0] = gf100_ce_new,
1582 .disp = gt215_disp_new, 1582 .disp = gt215_disp_new,
1583 .dma = gf100_dma_new, 1583 .dma = gf100_dma_new,
@@ -1612,6 +1612,7 @@ nvd7_chipset = {
1612 .pci = gf106_pci_new, 1612 .pci = gf106_pci_new,
1613 .therm = gf119_therm_new, 1613 .therm = gf119_therm_new,
1614 .timer = nv41_timer_new, 1614 .timer = nv41_timer_new,
1615 .volt = gf100_volt_new,
1615 .ce[0] = gf100_ce_new, 1616 .ce[0] = gf100_ce_new,
1616 .disp = gf119_disp_new, 1617 .disp = gf119_disp_new,
1617 .dma = gf119_dma_new, 1618 .dma = gf119_dma_new,
@@ -1647,7 +1648,7 @@ nvd9_chipset = {
1647 .pmu = gf119_pmu_new, 1648 .pmu = gf119_pmu_new,
1648 .therm = gf119_therm_new, 1649 .therm = gf119_therm_new,
1649 .timer = nv41_timer_new, 1650 .timer = nv41_timer_new,
1650 .volt = nv40_volt_new, 1651 .volt = gf100_volt_new,
1651 .ce[0] = gf100_ce_new, 1652 .ce[0] = gf100_ce_new,
1652 .disp = gf119_disp_new, 1653 .disp = gf119_disp_new,
1653 .dma = gf119_dma_new, 1654 .dma = gf119_dma_new,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c
index 62ad0300cfa5..0030cd9543b2 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c
@@ -1665,14 +1665,31 @@ nvkm_device_pci_new(struct pci_dev *pci_dev, const char *cfg, const char *dbg,
1665 *pdevice = &pdev->device; 1665 *pdevice = &pdev->device;
1666 pdev->pdev = pci_dev; 1666 pdev->pdev = pci_dev;
1667 1667
1668 return nvkm_device_ctor(&nvkm_device_pci_func, quirk, &pci_dev->dev, 1668 ret = nvkm_device_ctor(&nvkm_device_pci_func, quirk, &pci_dev->dev,
1669 pci_is_pcie(pci_dev) ? NVKM_DEVICE_PCIE : 1669 pci_is_pcie(pci_dev) ? NVKM_DEVICE_PCIE :
1670 pci_find_capability(pci_dev, PCI_CAP_ID_AGP) ? 1670 pci_find_capability(pci_dev, PCI_CAP_ID_AGP) ?
1671 NVKM_DEVICE_AGP : NVKM_DEVICE_PCI, 1671 NVKM_DEVICE_AGP : NVKM_DEVICE_PCI,
1672 (u64)pci_domain_nr(pci_dev->bus) << 32 | 1672 (u64)pci_domain_nr(pci_dev->bus) << 32 |
1673 pci_dev->bus->number << 16 | 1673 pci_dev->bus->number << 16 |
1674 PCI_SLOT(pci_dev->devfn) << 8 | 1674 PCI_SLOT(pci_dev->devfn) << 8 |
1675 PCI_FUNC(pci_dev->devfn), name, 1675 PCI_FUNC(pci_dev->devfn), name,
1676 cfg, dbg, detect, mmio, subdev_mask, 1676 cfg, dbg, detect, mmio, subdev_mask,
1677 &pdev->device); 1677 &pdev->device);
1678
1679 if (ret)
1680 return ret;
1681
1682 /*
1683 * Set a preliminary DMA mask based on the .dma_bits member of the
1684 * MMU subdevice. This allows other subdevices to create DMA mappings
1685 * in their init() or oneinit() methods, which may be called before the
1686 * TTM layer sets the DMA mask definitively.
1687 * This is necessary for platforms where the default DMA mask of 32
1688 * does not cover any system memory, i.e., when all RAM is > 4 GB.
1689 */
1690 if (subdev_mask & BIT(NVKM_SUBDEV_MMU))
1691 dma_set_mask_and_coherent(&pci_dev->dev,
1692 DMA_BIT_MASK(pdev->device.mmu->dma_bits));
1693
1694 return 0;
1678} 1695}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c
index 1bb9d661e9b3..4510cb6e10a8 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c
@@ -45,14 +45,6 @@ static const struct nvkm_output_func
45g94_sor_output_func = { 45g94_sor_output_func = {
46}; 46};
47 47
48int
49g94_sor_output_new(struct nvkm_disp *disp, int index,
50 struct dcb_output *dcbE, struct nvkm_output **poutp)
51{
52 return nvkm_output_new_(&g94_sor_output_func, disp,
53 index, dcbE, poutp);
54}
55
56/******************************************************************************* 48/*******************************************************************************
57 * DisplayPort 49 * DisplayPort
58 ******************************************************************************/ 50 ******************************************************************************/
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c
index f1e15a4d4f64..b4e3c50badc7 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c
@@ -187,6 +187,7 @@ nv30_gr = {
187 { -1, -1, 0x038a, &nv04_gr_object }, /* ifc (nv30) */ 187 { -1, -1, 0x038a, &nv04_gr_object }, /* ifc (nv30) */
188 { -1, -1, 0x039e, &nv04_gr_object }, /* swzsurf (nv30) */ 188 { -1, -1, 0x039e, &nv04_gr_object }, /* swzsurf (nv30) */
189 { -1, -1, 0x0397, &nv04_gr_object }, /* rankine */ 189 { -1, -1, 0x0397, &nv04_gr_object }, /* rankine */
190 { -1, -1, 0x0597, &nv04_gr_object }, /* kelvin */
190 {} 191 {}
191 } 192 }
192}; 193};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c
index 300f5ed5de0b..e7ed04b935cd 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c
@@ -123,6 +123,7 @@ nv34_gr = {
123 { -1, -1, 0x0389, &nv04_gr_object }, /* sifm (nv30) */ 123 { -1, -1, 0x0389, &nv04_gr_object }, /* sifm (nv30) */
124 { -1, -1, 0x038a, &nv04_gr_object }, /* ifc (nv30) */ 124 { -1, -1, 0x038a, &nv04_gr_object }, /* ifc (nv30) */
125 { -1, -1, 0x039e, &nv04_gr_object }, /* swzsurf (nv30) */ 125 { -1, -1, 0x039e, &nv04_gr_object }, /* swzsurf (nv30) */
126 { -1, -1, 0x0597, &nv04_gr_object }, /* kelvin */
126 { -1, -1, 0x0697, &nv04_gr_object }, /* rankine */ 127 { -1, -1, 0x0697, &nv04_gr_object }, /* rankine */
127 {} 128 {}
128 } 129 }
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c
index 740df0f52c38..5e8abacbacc6 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c
@@ -124,6 +124,7 @@ nv35_gr = {
124 { -1, -1, 0x038a, &nv04_gr_object }, /* ifc (nv30) */ 124 { -1, -1, 0x038a, &nv04_gr_object }, /* ifc (nv30) */
125 { -1, -1, 0x039e, &nv04_gr_object }, /* swzsurf (nv30) */ 125 { -1, -1, 0x039e, &nv04_gr_object }, /* swzsurf (nv30) */
126 { -1, -1, 0x0497, &nv04_gr_object }, /* rankine */ 126 { -1, -1, 0x0497, &nv04_gr_object }, /* rankine */
127 { -1, -1, 0x0597, &nv04_gr_object }, /* kelvin */
127 {} 128 {}
128 } 129 }
129}; 130};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c
index 370dcd8ff7b5..6eff637ac301 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c
@@ -84,7 +84,7 @@ nv50_bar_oneinit(struct nvkm_bar *base)
84 start = 0x0100000000ULL; 84 start = 0x0100000000ULL;
85 limit = start + device->func->resource_size(device, 3); 85 limit = start + device->func->resource_size(device, 3);
86 86
87 ret = nvkm_vm_new(device, start, limit, start, &bar3_lock, &vm); 87 ret = nvkm_vm_new(device, start, limit - start, start, &bar3_lock, &vm);
88 if (ret) 88 if (ret)
89 return ret; 89 return ret;
90 90
@@ -117,7 +117,7 @@ nv50_bar_oneinit(struct nvkm_bar *base)
117 start = 0x0000000000ULL; 117 start = 0x0000000000ULL;
118 limit = start + device->func->resource_size(device, 1); 118 limit = start + device->func->resource_size(device, 1);
119 119
120 ret = nvkm_vm_new(device, start, limit--, start, &bar1_lock, &vm); 120 ret = nvkm_vm_new(device, start, limit-- - start, start, &bar1_lock, &vm);
121 if (ret) 121 if (ret)
122 return ret; 122 return ret;
123 123
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/Kbuild
index dbcb0ef21587..be57220a2e01 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/Kbuild
@@ -31,6 +31,7 @@ nvkm-y += nvkm/subdev/bios/timing.o
31nvkm-y += nvkm/subdev/bios/therm.o 31nvkm-y += nvkm/subdev/bios/therm.o
32nvkm-y += nvkm/subdev/bios/vmap.o 32nvkm-y += nvkm/subdev/bios/vmap.o
33nvkm-y += nvkm/subdev/bios/volt.o 33nvkm-y += nvkm/subdev/bios/volt.o
34nvkm-y += nvkm/subdev/bios/vpstate.o
34nvkm-y += nvkm/subdev/bios/xpio.o 35nvkm-y += nvkm/subdev/bios/xpio.o
35nvkm-y += nvkm/subdev/bios/M0203.o 36nvkm-y += nvkm/subdev/bios/M0203.o
36nvkm-y += nvkm/subdev/bios/M0205.o 37nvkm-y += nvkm/subdev/bios/M0205.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/iccsense.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/iccsense.c
index 084328028af1..aafd5e17b1c8 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/iccsense.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/iccsense.c
@@ -23,6 +23,7 @@
23 */ 23 */
24#include <subdev/bios.h> 24#include <subdev/bios.h>
25#include <subdev/bios/bit.h> 25#include <subdev/bios/bit.h>
26#include <subdev/bios/extdev.h>
26#include <subdev/bios/iccsense.h> 27#include <subdev/bios/iccsense.h>
27 28
28static u16 29static u16
@@ -77,23 +78,47 @@ nvbios_iccsense_parse(struct nvkm_bios *bios, struct nvbios_iccsense *iccsense)
77 return -ENOMEM; 78 return -ENOMEM;
78 79
79 for (i = 0; i < cnt; ++i) { 80 for (i = 0; i < cnt; ++i) {
81 struct nvbios_extdev_func extdev;
80 struct pwr_rail_t *rail = &iccsense->rail[i]; 82 struct pwr_rail_t *rail = &iccsense->rail[i];
83 u8 res_start = 0;
84 int r;
85
81 entry = table + hdr + i * len; 86 entry = table + hdr + i * len;
82 87
83 switch(ver) { 88 switch(ver) {
84 case 0x10: 89 case 0x10:
85 rail->mode = nvbios_rd08(bios, entry + 0x1); 90 rail->mode = nvbios_rd08(bios, entry + 0x1);
86 rail->extdev_id = nvbios_rd08(bios, entry + 0x2); 91 rail->extdev_id = nvbios_rd08(bios, entry + 0x2);
87 rail->resistor_mohm = nvbios_rd08(bios, entry + 0x3); 92 res_start = 0x3;
88 rail->rail = nvbios_rd08(bios, entry + 0x4);
89 break; 93 break;
90 case 0x20: 94 case 0x20:
91 rail->mode = nvbios_rd08(bios, entry); 95 rail->mode = nvbios_rd08(bios, entry);
92 rail->extdev_id = nvbios_rd08(bios, entry + 0x1); 96 rail->extdev_id = nvbios_rd08(bios, entry + 0x1);
93 rail->resistor_mohm = nvbios_rd08(bios, entry + 0x5); 97 res_start = 0x5;
94 rail->rail = nvbios_rd08(bios, entry + 0x6); 98 break;
99 };
100
101 if (nvbios_extdev_parse(bios, rail->extdev_id, &extdev))
102 continue;
103
104 switch (extdev.type) {
105 case NVBIOS_EXTDEV_INA209:
106 case NVBIOS_EXTDEV_INA219:
107 rail->resistor_count = 1;
108 break;
109 case NVBIOS_EXTDEV_INA3221:
110 rail->resistor_count = 3;
111 break;
112 default:
113 rail->resistor_count = 0;
95 break; 114 break;
96 }; 115 };
116
117 for (r = 0; r < rail->resistor_count; ++r) {
118 rail->resistors[r].mohm = nvbios_rd08(bios, entry + res_start + r * 2);
119 rail->resistors[r].enabled = !(nvbios_rd08(bios, entry + res_start + r * 2 + 1) & 0x40);
120 }
121 rail->config = nvbios_rd16(bios, entry + res_start + rail->resistor_count * 2);
97 } 122 }
98 123
99 return 0; 124 return 0;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/vmap.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/vmap.c
index 2f13db745948..32bd8b1d154f 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/vmap.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/vmap.c
@@ -61,7 +61,17 @@ nvbios_vmap_parse(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
61 memset(info, 0x00, sizeof(*info)); 61 memset(info, 0x00, sizeof(*info));
62 switch (!!vmap * *ver) { 62 switch (!!vmap * *ver) {
63 case 0x10: 63 case 0x10:
64 info->max0 = 0xff;
65 info->max1 = 0xff;
66 info->max2 = 0xff;
67 break;
64 case 0x20: 68 case 0x20:
69 info->max0 = nvbios_rd08(bios, vmap + 0x7);
70 info->max1 = nvbios_rd08(bios, vmap + 0x8);
71 if (*len >= 0xc)
72 info->max2 = nvbios_rd08(bios, vmap + 0xc);
73 else
74 info->max2 = 0xff;
65 break; 75 break;
66 } 76 }
67 return vmap; 77 return vmap;
@@ -95,7 +105,7 @@ nvbios_vmap_entry_parse(struct nvkm_bios *bios, int idx, u8 *ver, u8 *len,
95 info->arg[2] = nvbios_rd32(bios, vmap + 0x10); 105 info->arg[2] = nvbios_rd32(bios, vmap + 0x10);
96 break; 106 break;
97 case 0x20: 107 case 0x20:
98 info->unk0 = nvbios_rd08(bios, vmap + 0x00); 108 info->mode = nvbios_rd08(bios, vmap + 0x00);
99 info->link = nvbios_rd08(bios, vmap + 0x01); 109 info->link = nvbios_rd08(bios, vmap + 0x01);
100 info->min = nvbios_rd32(bios, vmap + 0x02); 110 info->min = nvbios_rd32(bios, vmap + 0x02);
101 info->max = nvbios_rd32(bios, vmap + 0x06); 111 info->max = nvbios_rd32(bios, vmap + 0x06);
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/volt.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/volt.c
index 6e0a33648be9..4504822ace51 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/volt.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/volt.c
@@ -75,20 +75,24 @@ nvbios_volt_parse(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
75 case 0x12: 75 case 0x12:
76 info->type = NVBIOS_VOLT_GPIO; 76 info->type = NVBIOS_VOLT_GPIO;
77 info->vidmask = nvbios_rd08(bios, volt + 0x04); 77 info->vidmask = nvbios_rd08(bios, volt + 0x04);
78 info->ranged = false;
78 break; 79 break;
79 case 0x20: 80 case 0x20:
80 info->type = NVBIOS_VOLT_GPIO; 81 info->type = NVBIOS_VOLT_GPIO;
81 info->vidmask = nvbios_rd08(bios, volt + 0x05); 82 info->vidmask = nvbios_rd08(bios, volt + 0x05);
83 info->ranged = false;
82 break; 84 break;
83 case 0x30: 85 case 0x30:
84 info->type = NVBIOS_VOLT_GPIO; 86 info->type = NVBIOS_VOLT_GPIO;
85 info->vidmask = nvbios_rd08(bios, volt + 0x04); 87 info->vidmask = nvbios_rd08(bios, volt + 0x04);
88 info->ranged = false;
86 break; 89 break;
87 case 0x40: 90 case 0x40:
88 info->type = NVBIOS_VOLT_GPIO; 91 info->type = NVBIOS_VOLT_GPIO;
89 info->base = nvbios_rd32(bios, volt + 0x04); 92 info->base = nvbios_rd32(bios, volt + 0x04);
90 info->step = nvbios_rd16(bios, volt + 0x08); 93 info->step = nvbios_rd16(bios, volt + 0x08);
91 info->vidmask = nvbios_rd08(bios, volt + 0x0b); 94 info->vidmask = nvbios_rd08(bios, volt + 0x0b);
95 info->ranged = true; /* XXX: find the flag byte */
92 /*XXX*/ 96 /*XXX*/
93 info->min = 0; 97 info->min = 0;
94 info->max = info->base; 98 info->max = info->base;
@@ -104,9 +108,11 @@ nvbios_volt_parse(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
104 info->pwm_freq = nvbios_rd32(bios, volt + 0x5) / 1000; 108 info->pwm_freq = nvbios_rd32(bios, volt + 0x5) / 1000;
105 info->pwm_range = nvbios_rd32(bios, volt + 0x16); 109 info->pwm_range = nvbios_rd32(bios, volt + 0x16);
106 } else { 110 } else {
107 info->type = NVBIOS_VOLT_GPIO; 111 info->type = NVBIOS_VOLT_GPIO;
108 info->vidmask = nvbios_rd08(bios, volt + 0x06); 112 info->vidmask = nvbios_rd08(bios, volt + 0x06);
109 info->step = nvbios_rd16(bios, volt + 0x16); 113 info->step = nvbios_rd16(bios, volt + 0x16);
114 info->ranged =
115 !!(nvbios_rd08(bios, volt + 0x4) & 0x2);
110 } 116 }
111 break; 117 break;
112 } 118 }
@@ -142,7 +148,10 @@ nvbios_volt_entry_parse(struct nvkm_bios *bios, int idx, u8 *ver, u8 *len,
142 info->vid = nvbios_rd08(bios, volt + 0x01) >> 2; 148 info->vid = nvbios_rd08(bios, volt + 0x01) >> 2;
143 break; 149 break;
144 case 0x40: 150 case 0x40:
151 break;
145 case 0x50: 152 case 0x50:
153 info->voltage = nvbios_rd32(bios, volt) & 0x001fffff;
154 info->vid = (nvbios_rd32(bios, volt) >> 23) & 0xff;
146 break; 155 break;
147 } 156 }
148 return volt; 157 return volt;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/vpstate.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/vpstate.c
new file mode 100644
index 000000000000..f199270163d2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/vpstate.c
@@ -0,0 +1,82 @@
1/*
2 * Copyright 2016 Karol Herbst
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Authors: Karol Herbst
23 */
24#include <subdev/bios.h>
25#include <subdev/bios/bit.h>
26#include <subdev/bios/vpstate.h>
27
28static u32
29nvbios_vpstate_offset(struct nvkm_bios *b)
30{
31 struct bit_entry bit_P;
32
33 if (!bit_entry(b, 'P', &bit_P)) {
34 if (bit_P.version == 2)
35 return nvbios_rd32(b, bit_P.offset + 0x38);
36 }
37
38 return 0x0000;
39}
40
41int
42nvbios_vpstate_parse(struct nvkm_bios *b, struct nvbios_vpstate_header *h)
43{
44 if (!h)
45 return -EINVAL;
46
47 h->offset = nvbios_vpstate_offset(b);
48 if (!h->offset)
49 return -ENODEV;
50
51 h->version = nvbios_rd08(b, h->offset);
52 switch (h->version) {
53 case 0x10:
54 h->hlen = nvbios_rd08(b, h->offset + 0x1);
55 h->elen = nvbios_rd08(b, h->offset + 0x2);
56 h->slen = nvbios_rd08(b, h->offset + 0x3);
57 h->scount = nvbios_rd08(b, h->offset + 0x4);
58 h->ecount = nvbios_rd08(b, h->offset + 0x5);
59
60 h->base_id = nvbios_rd08(b, h->offset + 0x0f);
61 h->boost_id = nvbios_rd08(b, h->offset + 0x10);
62 h->tdp_id = nvbios_rd08(b, h->offset + 0x11);
63 return 0;
64 default:
65 return -EINVAL;
66 }
67}
68
69int
70nvbios_vpstate_entry(struct nvkm_bios *b, struct nvbios_vpstate_header *h,
71 u8 idx, struct nvbios_vpstate_entry *e)
72{
73 u32 offset;
74
75 if (!e || !h || idx > h->ecount)
76 return -EINVAL;
77
78 offset = h->offset + h->hlen + idx * (h->elen + (h->slen * h->scount));
79 e->pstate = nvbios_rd08(b, offset);
80 e->clock_mhz = nvbios_rd16(b, offset + 0x5);
81 return 0;
82}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c
index 7102c25320fc..fa1c12185e19 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c
@@ -27,6 +27,7 @@
27#include <subdev/bios/boost.h> 27#include <subdev/bios/boost.h>
28#include <subdev/bios/cstep.h> 28#include <subdev/bios/cstep.h>
29#include <subdev/bios/perf.h> 29#include <subdev/bios/perf.h>
30#include <subdev/bios/vpstate.h>
30#include <subdev/fb.h> 31#include <subdev/fb.h>
31#include <subdev/therm.h> 32#include <subdev/therm.h>
32#include <subdev/volt.h> 33#include <subdev/volt.h>
@@ -74,6 +75,88 @@ nvkm_clk_adjust(struct nvkm_clk *clk, bool adjust,
74/****************************************************************************** 75/******************************************************************************
75 * C-States 76 * C-States
76 *****************************************************************************/ 77 *****************************************************************************/
78static bool
79nvkm_cstate_valid(struct nvkm_clk *clk, struct nvkm_cstate *cstate,
80 u32 max_volt, int temp)
81{
82 const struct nvkm_domain *domain = clk->domains;
83 struct nvkm_volt *volt = clk->subdev.device->volt;
84 int voltage;
85
86 while (domain && domain->name != nv_clk_src_max) {
87 if (domain->flags & NVKM_CLK_DOM_FLAG_VPSTATE) {
88 u32 freq = cstate->domain[domain->name];
89 switch (clk->boost_mode) {
90 case NVKM_CLK_BOOST_NONE:
91 if (clk->base_khz && freq > clk->base_khz)
92 return false;
93 case NVKM_CLK_BOOST_BIOS:
94 if (clk->boost_khz && freq > clk->boost_khz)
95 return false;
96 }
97 }
98 domain++;
99 }
100
101 if (!volt)
102 return true;
103
104 voltage = nvkm_volt_map(volt, cstate->voltage, temp);
105 if (voltage < 0)
106 return false;
107 return voltage <= min(max_volt, volt->max_uv);
108}
109
110static struct nvkm_cstate *
111nvkm_cstate_find_best(struct nvkm_clk *clk, struct nvkm_pstate *pstate,
112 struct nvkm_cstate *start)
113{
114 struct nvkm_device *device = clk->subdev.device;
115 struct nvkm_volt *volt = device->volt;
116 struct nvkm_cstate *cstate;
117 int max_volt;
118
119 if (!pstate || !start)
120 return NULL;
121
122 if (!volt)
123 return start;
124
125 max_volt = volt->max_uv;
126 if (volt->max0_id != 0xff)
127 max_volt = min(max_volt,
128 nvkm_volt_map(volt, volt->max0_id, clk->temp));
129 if (volt->max1_id != 0xff)
130 max_volt = min(max_volt,
131 nvkm_volt_map(volt, volt->max1_id, clk->temp));
132 if (volt->max2_id != 0xff)
133 max_volt = min(max_volt,
134 nvkm_volt_map(volt, volt->max2_id, clk->temp));
135
136 for (cstate = start; &cstate->head != &pstate->list;
137 cstate = list_entry(cstate->head.prev, typeof(*cstate), head)) {
138 if (nvkm_cstate_valid(clk, cstate, max_volt, clk->temp))
139 break;
140 }
141
142 return cstate;
143}
144
145static struct nvkm_cstate *
146nvkm_cstate_get(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei)
147{
148 struct nvkm_cstate *cstate;
149 if (cstatei == NVKM_CLK_CSTATE_HIGHEST)
150 return list_last_entry(&pstate->list, typeof(*cstate), head);
151 else {
152 list_for_each_entry(cstate, &pstate->list, head) {
153 if (cstate->id == cstatei)
154 return cstate;
155 }
156 }
157 return NULL;
158}
159
77static int 160static int
78nvkm_cstate_prog(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei) 161nvkm_cstate_prog(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei)
79{ 162{
@@ -85,7 +168,8 @@ nvkm_cstate_prog(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei)
85 int ret; 168 int ret;
86 169
87 if (!list_empty(&pstate->list)) { 170 if (!list_empty(&pstate->list)) {
88 cstate = list_entry(pstate->list.prev, typeof(*cstate), head); 171 cstate = nvkm_cstate_get(clk, pstate, cstatei);
172 cstate = nvkm_cstate_find_best(clk, pstate, cstate);
89 } else { 173 } else {
90 cstate = &pstate->base; 174 cstate = &pstate->base;
91 } 175 }
@@ -99,7 +183,8 @@ nvkm_cstate_prog(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei)
99 } 183 }
100 184
101 if (volt) { 185 if (volt) {
102 ret = nvkm_volt_set_id(volt, cstate->voltage, +1); 186 ret = nvkm_volt_set_id(volt, cstate->voltage,
187 pstate->base.voltage, clk->temp, +1);
103 if (ret && ret != -ENODEV) { 188 if (ret && ret != -ENODEV) {
104 nvkm_error(subdev, "failed to raise voltage: %d\n", ret); 189 nvkm_error(subdev, "failed to raise voltage: %d\n", ret);
105 return ret; 190 return ret;
@@ -113,7 +198,8 @@ nvkm_cstate_prog(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei)
113 } 198 }
114 199
115 if (volt) { 200 if (volt) {
116 ret = nvkm_volt_set_id(volt, cstate->voltage, -1); 201 ret = nvkm_volt_set_id(volt, cstate->voltage,
202 pstate->base.voltage, clk->temp, -1);
117 if (ret && ret != -ENODEV) 203 if (ret && ret != -ENODEV)
118 nvkm_error(subdev, "failed to lower voltage: %d\n", ret); 204 nvkm_error(subdev, "failed to lower voltage: %d\n", ret);
119 } 205 }
@@ -138,6 +224,7 @@ static int
138nvkm_cstate_new(struct nvkm_clk *clk, int idx, struct nvkm_pstate *pstate) 224nvkm_cstate_new(struct nvkm_clk *clk, int idx, struct nvkm_pstate *pstate)
139{ 225{
140 struct nvkm_bios *bios = clk->subdev.device->bios; 226 struct nvkm_bios *bios = clk->subdev.device->bios;
227 struct nvkm_volt *volt = clk->subdev.device->volt;
141 const struct nvkm_domain *domain = clk->domains; 228 const struct nvkm_domain *domain = clk->domains;
142 struct nvkm_cstate *cstate = NULL; 229 struct nvkm_cstate *cstate = NULL;
143 struct nvbios_cstepX cstepX; 230 struct nvbios_cstepX cstepX;
@@ -148,12 +235,16 @@ nvkm_cstate_new(struct nvkm_clk *clk, int idx, struct nvkm_pstate *pstate)
148 if (!data) 235 if (!data)
149 return -ENOENT; 236 return -ENOENT;
150 237
238 if (volt && nvkm_volt_map_min(volt, cstepX.voltage) > volt->max_uv)
239 return -EINVAL;
240
151 cstate = kzalloc(sizeof(*cstate), GFP_KERNEL); 241 cstate = kzalloc(sizeof(*cstate), GFP_KERNEL);
152 if (!cstate) 242 if (!cstate)
153 return -ENOMEM; 243 return -ENOMEM;
154 244
155 *cstate = pstate->base; 245 *cstate = pstate->base;
156 cstate->voltage = cstepX.voltage; 246 cstate->voltage = cstepX.voltage;
247 cstate->id = idx;
157 248
158 while (domain && domain->name != nv_clk_src_max) { 249 while (domain && domain->name != nv_clk_src_max) {
159 if (domain->flags & NVKM_CLK_DOM_FLAG_CORE) { 250 if (domain->flags & NVKM_CLK_DOM_FLAG_CORE) {
@@ -175,7 +266,7 @@ static int
175nvkm_pstate_prog(struct nvkm_clk *clk, int pstatei) 266nvkm_pstate_prog(struct nvkm_clk *clk, int pstatei)
176{ 267{
177 struct nvkm_subdev *subdev = &clk->subdev; 268 struct nvkm_subdev *subdev = &clk->subdev;
178 struct nvkm_ram *ram = subdev->device->fb->ram; 269 struct nvkm_fb *fb = subdev->device->fb;
179 struct nvkm_pci *pci = subdev->device->pci; 270 struct nvkm_pci *pci = subdev->device->pci;
180 struct nvkm_pstate *pstate; 271 struct nvkm_pstate *pstate;
181 int ret, idx = 0; 272 int ret, idx = 0;
@@ -190,7 +281,8 @@ nvkm_pstate_prog(struct nvkm_clk *clk, int pstatei)
190 281
191 nvkm_pcie_set_link(pci, pstate->pcie_speed, pstate->pcie_width); 282 nvkm_pcie_set_link(pci, pstate->pcie_speed, pstate->pcie_width);
192 283
193 if (ram && ram->func->calc) { 284 if (fb && fb->ram && fb->ram->func->calc) {
285 struct nvkm_ram *ram = fb->ram;
194 int khz = pstate->base.domain[nv_clk_src_mem]; 286 int khz = pstate->base.domain[nv_clk_src_mem];
195 do { 287 do {
196 ret = ram->func->calc(ram, khz); 288 ret = ram->func->calc(ram, khz);
@@ -200,7 +292,7 @@ nvkm_pstate_prog(struct nvkm_clk *clk, int pstatei)
200 ram->func->tidy(ram); 292 ram->func->tidy(ram);
201 } 293 }
202 294
203 return nvkm_cstate_prog(clk, pstate, 0); 295 return nvkm_cstate_prog(clk, pstate, NVKM_CLK_CSTATE_HIGHEST);
204} 296}
205 297
206static void 298static void
@@ -214,14 +306,14 @@ nvkm_pstate_work(struct work_struct *work)
214 return; 306 return;
215 clk->pwrsrc = power_supply_is_system_supplied(); 307 clk->pwrsrc = power_supply_is_system_supplied();
216 308
217 nvkm_trace(subdev, "P %d PWR %d U(AC) %d U(DC) %d A %d T %d D %d\n", 309 nvkm_trace(subdev, "P %d PWR %d U(AC) %d U(DC) %d A %d T %d°C D %d\n",
218 clk->pstate, clk->pwrsrc, clk->ustate_ac, clk->ustate_dc, 310 clk->pstate, clk->pwrsrc, clk->ustate_ac, clk->ustate_dc,
219 clk->astate, clk->tstate, clk->dstate); 311 clk->astate, clk->temp, clk->dstate);
220 312
221 pstate = clk->pwrsrc ? clk->ustate_ac : clk->ustate_dc; 313 pstate = clk->pwrsrc ? clk->ustate_ac : clk->ustate_dc;
222 if (clk->state_nr && pstate != -1) { 314 if (clk->state_nr && pstate != -1) {
223 pstate = (pstate < 0) ? clk->astate : pstate; 315 pstate = (pstate < 0) ? clk->astate : pstate;
224 pstate = min(pstate, clk->state_nr - 1 + clk->tstate); 316 pstate = min(pstate, clk->state_nr - 1);
225 pstate = max(pstate, clk->dstate); 317 pstate = max(pstate, clk->dstate);
226 } else { 318 } else {
227 pstate = clk->pstate = -1; 319 pstate = clk->pstate = -1;
@@ -448,13 +540,12 @@ nvkm_clk_astate(struct nvkm_clk *clk, int req, int rel, bool wait)
448} 540}
449 541
450int 542int
451nvkm_clk_tstate(struct nvkm_clk *clk, int req, int rel) 543nvkm_clk_tstate(struct nvkm_clk *clk, u8 temp)
452{ 544{
453 if (!rel) clk->tstate = req; 545 if (clk->temp == temp)
454 if ( rel) clk->tstate += rel; 546 return 0;
455 clk->tstate = min(clk->tstate, 0); 547 clk->temp = temp;
456 clk->tstate = max(clk->tstate, -(clk->state_nr - 1)); 548 return nvkm_pstate_calc(clk, false);
457 return nvkm_pstate_calc(clk, true);
458} 549}
459 550
460int 551int
@@ -524,9 +615,9 @@ nvkm_clk_init(struct nvkm_subdev *subdev)
524 return clk->func->init(clk); 615 return clk->func->init(clk);
525 616
526 clk->astate = clk->state_nr - 1; 617 clk->astate = clk->state_nr - 1;
527 clk->tstate = 0;
528 clk->dstate = 0; 618 clk->dstate = 0;
529 clk->pstate = -1; 619 clk->pstate = -1;
620 clk->temp = 90; /* reasonable default value */
530 nvkm_pstate_calc(clk, true); 621 nvkm_pstate_calc(clk, true);
531 return 0; 622 return 0;
532} 623}
@@ -561,10 +652,22 @@ int
561nvkm_clk_ctor(const struct nvkm_clk_func *func, struct nvkm_device *device, 652nvkm_clk_ctor(const struct nvkm_clk_func *func, struct nvkm_device *device,
562 int index, bool allow_reclock, struct nvkm_clk *clk) 653 int index, bool allow_reclock, struct nvkm_clk *clk)
563{ 654{
655 struct nvkm_subdev *subdev = &clk->subdev;
656 struct nvkm_bios *bios = device->bios;
564 int ret, idx, arglen; 657 int ret, idx, arglen;
565 const char *mode; 658 const char *mode;
659 struct nvbios_vpstate_header h;
660
661 nvkm_subdev_ctor(&nvkm_clk, device, index, subdev);
662
663 if (bios && !nvbios_vpstate_parse(bios, &h)) {
664 struct nvbios_vpstate_entry base, boost;
665 if (!nvbios_vpstate_entry(bios, &h, h.boost_id, &boost))
666 clk->boost_khz = boost.clock_mhz * 1000;
667 if (!nvbios_vpstate_entry(bios, &h, h.base_id, &base))
668 clk->base_khz = base.clock_mhz * 1000;
669 }
566 670
567 nvkm_subdev_ctor(&nvkm_clk, device, index, &clk->subdev);
568 clk->func = func; 671 clk->func = func;
569 INIT_LIST_HEAD(&clk->states); 672 INIT_LIST_HEAD(&clk->states);
570 clk->domains = func->domains; 673 clk->domains = func->domains;
@@ -607,6 +710,8 @@ nvkm_clk_ctor(const struct nvkm_clk_func *func, struct nvkm_device *device,
607 if (mode) 710 if (mode)
608 clk->ustate_dc = nvkm_clk_nstate(clk, mode, arglen); 711 clk->ustate_dc = nvkm_clk_nstate(clk, mode, arglen);
609 712
713 clk->boost_mode = nvkm_longopt(device->cfgopt, "NvBoost",
714 NVKM_CLK_BOOST_NONE);
610 return 0; 715 return 0;
611} 716}
612 717
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c
index 89d5543118cf..7f67f9f5a550 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c
@@ -457,7 +457,7 @@ gf100_clk = {
457 { nv_clk_src_hubk06 , 0x00 }, 457 { nv_clk_src_hubk06 , 0x00 },
458 { nv_clk_src_hubk01 , 0x01 }, 458 { nv_clk_src_hubk01 , 0x01 },
459 { nv_clk_src_copy , 0x02 }, 459 { nv_clk_src_copy , 0x02 },
460 { nv_clk_src_gpc , 0x03, 0, "core", 2000 }, 460 { nv_clk_src_gpc , 0x03, NVKM_CLK_DOM_FLAG_VPSTATE, "core", 2000 },
461 { nv_clk_src_rop , 0x04 }, 461 { nv_clk_src_rop , 0x04 },
462 { nv_clk_src_mem , 0x05, 0, "memory", 1000 }, 462 { nv_clk_src_mem , 0x05, 0, "memory", 1000 },
463 { nv_clk_src_vdec , 0x06 }, 463 { nv_clk_src_vdec , 0x06 },
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c
index 06bc0d2d6ae1..0b37e3da7feb 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c
@@ -491,7 +491,7 @@ gk104_clk = {
491 .domains = { 491 .domains = {
492 { nv_clk_src_crystal, 0xff }, 492 { nv_clk_src_crystal, 0xff },
493 { nv_clk_src_href , 0xff }, 493 { nv_clk_src_href , 0xff },
494 { nv_clk_src_gpc , 0x00, NVKM_CLK_DOM_FLAG_CORE, "core", 2000 }, 494 { nv_clk_src_gpc , 0x00, NVKM_CLK_DOM_FLAG_CORE | NVKM_CLK_DOM_FLAG_VPSTATE, "core", 2000 },
495 { nv_clk_src_hubk07 , 0x01, NVKM_CLK_DOM_FLAG_CORE }, 495 { nv_clk_src_hubk07 , 0x01, NVKM_CLK_DOM_FLAG_CORE },
496 { nv_clk_src_rop , 0x02, NVKM_CLK_DOM_FLAG_CORE }, 496 { nv_clk_src_rop , 0x02, NVKM_CLK_DOM_FLAG_CORE },
497 { nv_clk_src_mem , 0x03, 0, "memory", 500 }, 497 { nv_clk_src_mem , 0x03, 0, "memory", 500 },
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c
index 76433cc66fff..3841ad6be99e 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c
@@ -50,24 +50,33 @@ gf100_fb_intr(struct nvkm_fb *base)
50} 50}
51 51
52int 52int
53gf100_fb_oneinit(struct nvkm_fb *fb) 53gf100_fb_oneinit(struct nvkm_fb *base)
54{ 54{
55 struct nvkm_device *device = fb->subdev.device; 55 struct gf100_fb *fb = gf100_fb(base);
56 struct nvkm_device *device = fb->base.subdev.device;
56 int ret, size = 0x1000; 57 int ret, size = 0x1000;
57 58
58 size = nvkm_longopt(device->cfgopt, "MmuDebugBufferSize", size); 59 size = nvkm_longopt(device->cfgopt, "MmuDebugBufferSize", size);
59 size = min(size, 0x1000); 60 size = min(size, 0x1000);
60 61
61 ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, size, 0x1000, 62 ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, size, 0x1000,
62 false, &fb->mmu_rd); 63 false, &fb->base.mmu_rd);
63 if (ret) 64 if (ret)
64 return ret; 65 return ret;
65 66
66 ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, size, 0x1000, 67 ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, size, 0x1000,
67 false, &fb->mmu_wr); 68 false, &fb->base.mmu_wr);
68 if (ret) 69 if (ret)
69 return ret; 70 return ret;
70 71
72 fb->r100c10_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
73 if (fb->r100c10_page) {
74 fb->r100c10 = dma_map_page(device->dev, fb->r100c10_page, 0,
75 PAGE_SIZE, DMA_BIDIRECTIONAL);
76 if (dma_mapping_error(device->dev, fb->r100c10))
77 return -EFAULT;
78 }
79
71 return 0; 80 return 0;
72} 81}
73 82
@@ -123,14 +132,6 @@ gf100_fb_new_(const struct nvkm_fb_func *func, struct nvkm_device *device,
123 nvkm_fb_ctor(func, device, index, &fb->base); 132 nvkm_fb_ctor(func, device, index, &fb->base);
124 *pfb = &fb->base; 133 *pfb = &fb->base;
125 134
126 fb->r100c10_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
127 if (fb->r100c10_page) {
128 fb->r100c10 = dma_map_page(device->dev, fb->r100c10_page, 0,
129 PAGE_SIZE, DMA_BIDIRECTIONAL);
130 if (dma_mapping_error(device->dev, fb->r100c10))
131 return -EFAULT;
132 }
133
134 return 0; 135 return 0;
135} 136}
136 137
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c
index 1b5fb02eab2a..0595e0722bfc 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c
@@ -210,6 +210,23 @@ nv50_fb_intr(struct nvkm_fb *base)
210 nvkm_fifo_chan_put(fifo, flags, &chan); 210 nvkm_fifo_chan_put(fifo, flags, &chan);
211} 211}
212 212
213static int
214nv50_fb_oneinit(struct nvkm_fb *base)
215{
216 struct nv50_fb *fb = nv50_fb(base);
217 struct nvkm_device *device = fb->base.subdev.device;
218
219 fb->r100c08_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
220 if (fb->r100c08_page) {
221 fb->r100c08 = dma_map_page(device->dev, fb->r100c08_page, 0,
222 PAGE_SIZE, DMA_BIDIRECTIONAL);
223 if (dma_mapping_error(device->dev, fb->r100c08))
224 return -EFAULT;
225 }
226
227 return 0;
228}
229
213static void 230static void
214nv50_fb_init(struct nvkm_fb *base) 231nv50_fb_init(struct nvkm_fb *base)
215{ 232{
@@ -245,6 +262,7 @@ nv50_fb_dtor(struct nvkm_fb *base)
245static const struct nvkm_fb_func 262static const struct nvkm_fb_func
246nv50_fb_ = { 263nv50_fb_ = {
247 .dtor = nv50_fb_dtor, 264 .dtor = nv50_fb_dtor,
265 .oneinit = nv50_fb_oneinit,
248 .init = nv50_fb_init, 266 .init = nv50_fb_init,
249 .intr = nv50_fb_intr, 267 .intr = nv50_fb_intr,
250 .ram_new = nv50_fb_ram_new, 268 .ram_new = nv50_fb_ram_new,
@@ -263,16 +281,6 @@ nv50_fb_new_(const struct nv50_fb_func *func, struct nvkm_device *device,
263 fb->func = func; 281 fb->func = func;
264 *pfb = &fb->base; 282 *pfb = &fb->base;
265 283
266 fb->r100c08_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
267 if (fb->r100c08_page) {
268 fb->r100c08 = dma_map_page(device->dev, fb->r100c08_page, 0,
269 PAGE_SIZE, DMA_BIDIRECTIONAL);
270 if (dma_mapping_error(device->dev, fb->r100c08))
271 return -EFAULT;
272 } else {
273 nvkm_warn(&fb->base.subdev, "failed 100c08 page alloc\n");
274 }
275
276 return 0; 284 return 0;
277} 285}
278 286
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.h
index b9ec0ae6723a..b60068b7d8f9 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.h
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.h
@@ -24,6 +24,7 @@ int gf100_ram_ctor(const struct nvkm_ram_func *, struct nvkm_fb *,
24int gf100_ram_get(struct nvkm_ram *, u64, u32, u32, u32, struct nvkm_mem **); 24int gf100_ram_get(struct nvkm_ram *, u64, u32, u32, u32, struct nvkm_mem **);
25void gf100_ram_put(struct nvkm_ram *, struct nvkm_mem **); 25void gf100_ram_put(struct nvkm_ram *, struct nvkm_mem **);
26 26
27int gk104_ram_ctor(struct nvkm_fb *, struct nvkm_ram **, u32);
27int gk104_ram_init(struct nvkm_ram *ram); 28int gk104_ram_init(struct nvkm_ram *ram);
28 29
29/* RAM type-specific MR calculation routines */ 30/* RAM type-specific MR calculation routines */
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c
index 1fa3ade468ae..7904fa41acef 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c
@@ -259,7 +259,9 @@ gk104_ram_calc_gddr5(struct gk104_ram *ram, u32 freq)
259 259
260 ram_mask(fuc, 0x10f808, 0x40000000, 0x40000000); 260 ram_mask(fuc, 0x10f808, 0x40000000, 0x40000000);
261 ram_block(fuc); 261 ram_block(fuc);
262 ram_wr32(fuc, 0x62c000, 0x0f0f0000); 262
263 if (nvkm_device_engine(ram->base.fb->subdev.device, NVKM_ENGINE_DISP))
264 ram_wr32(fuc, 0x62c000, 0x0f0f0000);
263 265
264 /* MR1: turn termination on early, for some reason.. */ 266 /* MR1: turn termination on early, for some reason.. */
265 if ((ram->base.mr[1] & 0x03c) != 0x030) { 267 if ((ram->base.mr[1] & 0x03c) != 0x030) {
@@ -658,7 +660,9 @@ gk104_ram_calc_gddr5(struct gk104_ram *ram, u32 freq)
658 gk104_ram_train(fuc, 0x80020000, 0x01000000); 660 gk104_ram_train(fuc, 0x80020000, 0x01000000);
659 661
660 ram_unblock(fuc); 662 ram_unblock(fuc);
661 ram_wr32(fuc, 0x62c000, 0x0f0f0f00); 663
664 if (nvkm_device_engine(ram->base.fb->subdev.device, NVKM_ENGINE_DISP))
665 ram_wr32(fuc, 0x62c000, 0x0f0f0f00);
662 666
663 if (next->bios.rammap_11_08_01) 667 if (next->bios.rammap_11_08_01)
664 data = 0x00000800; 668 data = 0x00000800;
@@ -706,7 +710,9 @@ gk104_ram_calc_sddr3(struct gk104_ram *ram, u32 freq)
706 710
707 ram_mask(fuc, 0x10f808, 0x40000000, 0x40000000); 711 ram_mask(fuc, 0x10f808, 0x40000000, 0x40000000);
708 ram_block(fuc); 712 ram_block(fuc);
709 ram_wr32(fuc, 0x62c000, 0x0f0f0000); 713
714 if (nvkm_device_engine(ram->base.fb->subdev.device, NVKM_ENGINE_DISP))
715 ram_wr32(fuc, 0x62c000, 0x0f0f0000);
710 716
711 if (vc == 1 && ram_have(fuc, gpio2E)) { 717 if (vc == 1 && ram_have(fuc, gpio2E)) {
712 u32 temp = ram_mask(fuc, gpio2E, 0x3000, fuc->r_func2E[1]); 718 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 ram_nsec(fuc, 1000); 942 ram_nsec(fuc, 1000);
937 943
938 ram_unblock(fuc); 944 ram_unblock(fuc);
939 ram_wr32(fuc, 0x62c000, 0x0f0f0f00); 945
946 if (nvkm_device_engine(ram->base.fb->subdev.device, NVKM_ENGINE_DISP))
947 ram_wr32(fuc, 0x62c000, 0x0f0f0f00);
940 948
941 if (next->bios.rammap_11_08_01) 949 if (next->bios.rammap_11_08_01)
942 data = 0x00000800; 950 data = 0x00000800;
@@ -1530,6 +1538,12 @@ gk104_ram_func = {
1530int 1538int
1531gk104_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram) 1539gk104_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram)
1532{ 1540{
1541 return gk104_ram_ctor(fb, pram, 0x022554);
1542}
1543
1544int
1545gk104_ram_ctor(struct nvkm_fb *fb, struct nvkm_ram **pram, u32 maskaddr)
1546{
1533 struct nvkm_subdev *subdev = &fb->subdev; 1547 struct nvkm_subdev *subdev = &fb->subdev;
1534 struct nvkm_device *device = subdev->device; 1548 struct nvkm_device *device = subdev->device;
1535 struct nvkm_bios *bios = device->bios; 1549 struct nvkm_bios *bios = device->bios;
@@ -1544,7 +1558,7 @@ gk104_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram)
1544 return -ENOMEM; 1558 return -ENOMEM;
1545 *pram = &ram->base; 1559 *pram = &ram->base;
1546 1560
1547 ret = gf100_ram_ctor(&gk104_ram_func, fb, 0x022554, &ram->base); 1561 ret = gf100_ram_ctor(&gk104_ram_func, fb, maskaddr, &ram->base);
1548 if (ret) 1562 if (ret)
1549 return ret; 1563 return ret;
1550 1564
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgm107.c
index 43d807f6ca71..ac862d1d77bd 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgm107.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgm107.c
@@ -23,18 +23,8 @@
23 */ 23 */
24#include "ram.h" 24#include "ram.h"
25 25
26static const struct nvkm_ram_func
27gm107_ram_func = {
28 .init = gk104_ram_init,
29 .get = gf100_ram_get,
30 .put = gf100_ram_put,
31};
32
33int 26int
34gm107_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram) 27gm107_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram)
35{ 28{
36 if (!(*pram = kzalloc(sizeof(**pram), GFP_KERNEL))) 29 return gk104_ram_ctor(fb, pram, 0x021c14);
37 return -ENOMEM;
38
39 return gf100_ram_ctor(&gm107_ram_func, fb, 0x021c14, *pram);
40} 30}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk20a.c
index b7159b338fac..1a4ab825852c 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk20a.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk20a.c
@@ -29,7 +29,7 @@ gk20a_ibus_init_ibus_ring(struct nvkm_subdev *ibus)
29 nvkm_mask(device, 0x137250, 0x3f, 0); 29 nvkm_mask(device, 0x137250, 0x3f, 0);
30 30
31 nvkm_mask(device, 0x000200, 0x20, 0); 31 nvkm_mask(device, 0x000200, 0x20, 0);
32 usleep_range(20, 30); 32 udelay(20);
33 nvkm_mask(device, 0x000200, 0x20, 0x20); 33 nvkm_mask(device, 0x000200, 0x20, 0x20);
34 34
35 nvkm_wr32(device, 0x12004c, 0x4); 35 nvkm_wr32(device, 0x12004c, 0x4);
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/iccsense/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/iccsense/base.c
index 41bd5d0f7692..658355fc9354 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/iccsense/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/iccsense/base.c
@@ -96,60 +96,12 @@ nvkm_iccsense_ina3221_read(struct nvkm_iccsense *iccsense,
96} 96}
97 97
98static void 98static void
99nvkm_iccsense_ina209_config(struct nvkm_iccsense *iccsense,
100 struct nvkm_iccsense_sensor *sensor)
101{
102 struct nvkm_subdev *subdev = &iccsense->subdev;
103 /* configuration:
104 * 0x0007: 0x0007 shunt and bus continous
105 * 0x0078: 0x0078 128 samples shunt
106 * 0x0780: 0x0780 128 samples bus
107 * 0x1800: 0x0000 +-40 mV shunt range
108 * 0x2000: 0x0000 16V FSR
109 */
110 u16 value = 0x07ff;
111 nvkm_debug(subdev, "config for sensor id %i: 0x%x\n", sensor->id, value);
112 nv_wr16i2cr(sensor->i2c, sensor->addr, 0x00, value);
113}
114
115static void
116nvkm_iccsense_ina3221_config(struct nvkm_iccsense *iccsense,
117 struct nvkm_iccsense_sensor *sensor)
118{
119 struct nvkm_subdev *subdev = &iccsense->subdev;
120 /* configuration:
121 * 0x0007: 0x0007 shunt and bus continous
122 * 0x0031: 0x0000 140 us conversion time shunt
123 * 0x01c0: 0x0000 140 us conversion time bus
124 * 0x0f00: 0x0f00 1024 samples
125 * 0x7000: 0x?000 channels
126 */
127 u16 value = 0x0e07;
128 if (sensor->rail_mask & 0x1)
129 value |= 0x1 << 14;
130 if (sensor->rail_mask & 0x2)
131 value |= 0x1 << 13;
132 if (sensor->rail_mask & 0x4)
133 value |= 0x1 << 12;
134 nvkm_debug(subdev, "config for sensor id %i: 0x%x\n", sensor->id, value);
135 nv_wr16i2cr(sensor->i2c, sensor->addr, 0x00, value);
136}
137
138static void
139nvkm_iccsense_sensor_config(struct nvkm_iccsense *iccsense, 99nvkm_iccsense_sensor_config(struct nvkm_iccsense *iccsense,
140 struct nvkm_iccsense_sensor *sensor) 100 struct nvkm_iccsense_sensor *sensor)
141{ 101{
142 switch (sensor->type) { 102 struct nvkm_subdev *subdev = &iccsense->subdev;
143 case NVBIOS_EXTDEV_INA209: 103 nvkm_trace(subdev, "write config of extdev %i: 0x%04x\n", sensor->id, sensor->config);
144 case NVBIOS_EXTDEV_INA219: 104 nv_wr16i2cr(sensor->i2c, sensor->addr, 0x00, sensor->config);
145 nvkm_iccsense_ina209_config(iccsense, sensor);
146 break;
147 case NVBIOS_EXTDEV_INA3221:
148 nvkm_iccsense_ina3221_config(iccsense, sensor);
149 break;
150 default:
151 break;
152 }
153} 105}
154 106
155int 107int
@@ -196,7 +148,6 @@ nvkm_iccsense_dtor(struct nvkm_subdev *subdev)
196static struct nvkm_iccsense_sensor* 148static struct nvkm_iccsense_sensor*
197nvkm_iccsense_create_sensor(struct nvkm_iccsense *iccsense, u8 id) 149nvkm_iccsense_create_sensor(struct nvkm_iccsense *iccsense, u8 id)
198{ 150{
199
200 struct nvkm_subdev *subdev = &iccsense->subdev; 151 struct nvkm_subdev *subdev = &iccsense->subdev;
201 struct nvkm_bios *bios = subdev->device->bios; 152 struct nvkm_bios *bios = subdev->device->bios;
202 struct nvkm_i2c *i2c = subdev->device->i2c; 153 struct nvkm_i2c *i2c = subdev->device->i2c;
@@ -245,7 +196,7 @@ nvkm_iccsense_create_sensor(struct nvkm_iccsense *iccsense, u8 id)
245 sensor->type = extdev.type; 196 sensor->type = extdev.type;
246 sensor->i2c = &i2c_bus->i2c; 197 sensor->i2c = &i2c_bus->i2c;
247 sensor->addr = addr; 198 sensor->addr = addr;
248 sensor->rail_mask = 0x0; 199 sensor->config = 0x0;
249 return sensor; 200 return sensor;
250} 201}
251 202
@@ -273,48 +224,56 @@ nvkm_iccsense_oneinit(struct nvkm_subdev *subdev)
273 224
274 iccsense->data_valid = true; 225 iccsense->data_valid = true;
275 for (i = 0; i < stbl.nr_entry; ++i) { 226 for (i = 0; i < stbl.nr_entry; ++i) {
276 struct pwr_rail_t *r = &stbl.rail[i]; 227 struct pwr_rail_t *pwr_rail = &stbl.rail[i];
277 struct nvkm_iccsense_rail *rail;
278 struct nvkm_iccsense_sensor *sensor; 228 struct nvkm_iccsense_sensor *sensor;
279 int (*read)(struct nvkm_iccsense *, 229 int r;
280 struct nvkm_iccsense_rail *);
281 230
282 if (!r->mode || r->resistor_mohm == 0) 231 if (pwr_rail->mode != 1 || !pwr_rail->resistor_count)
283 continue; 232 continue;
284 233
285 sensor = nvkm_iccsense_get_sensor(iccsense, r->extdev_id); 234 sensor = nvkm_iccsense_get_sensor(iccsense, pwr_rail->extdev_id);
286 if (!sensor) 235 if (!sensor)
287 continue; 236 continue;
288 237
289 switch (sensor->type) { 238 if (!sensor->config)
290 case NVBIOS_EXTDEV_INA209: 239 sensor->config = pwr_rail->config;
291 if (r->rail != 0) 240 else if (sensor->config != pwr_rail->config)
292 continue; 241 nvkm_error(subdev, "config mismatch found for extdev %i\n", pwr_rail->extdev_id);
293 read = nvkm_iccsense_ina209_read; 242
294 break; 243 for (r = 0; r < pwr_rail->resistor_count; ++r) {
295 case NVBIOS_EXTDEV_INA219: 244 struct nvkm_iccsense_rail *rail;
296 if (r->rail != 0) 245 struct pwr_rail_resistor_t *res = &pwr_rail->resistors[r];
246 int (*read)(struct nvkm_iccsense *,
247 struct nvkm_iccsense_rail *);
248
249 if (!res->mohm || !res->enabled)
297 continue; 250 continue;
298 read = nvkm_iccsense_ina219_read; 251
299 break; 252 switch (sensor->type) {
300 case NVBIOS_EXTDEV_INA3221: 253 case NVBIOS_EXTDEV_INA209:
301 if (r->rail >= 3) 254 read = nvkm_iccsense_ina209_read;
255 break;
256 case NVBIOS_EXTDEV_INA219:
257 read = nvkm_iccsense_ina219_read;
258 break;
259 case NVBIOS_EXTDEV_INA3221:
260 read = nvkm_iccsense_ina3221_read;
261 break;
262 default:
302 continue; 263 continue;
303 read = nvkm_iccsense_ina3221_read; 264 }
304 break; 265
305 default: 266 rail = kmalloc(sizeof(*rail), GFP_KERNEL);
306 continue; 267 if (!rail)
268 return -ENOMEM;
269
270 rail->read = read;
271 rail->sensor = sensor;
272 rail->idx = r;
273 rail->mohm = res->mohm;
274 nvkm_debug(subdev, "create rail for extdev %i: { idx: %i, mohm: %i }\n", pwr_rail->extdev_id, r, rail->mohm);
275 list_add_tail(&rail->head, &iccsense->rails);
307 } 276 }
308
309 rail = kmalloc(sizeof(*rail), GFP_KERNEL);
310 if (!rail)
311 return -ENOMEM;
312 sensor->rail_mask |= 1 << r->rail;
313 rail->read = read;
314 rail->sensor = sensor;
315 rail->idx = r->rail;
316 rail->mohm = r->resistor_mohm;
317 list_add_tail(&rail->head, &iccsense->rails);
318 } 277 }
319 return 0; 278 return 0;
320} 279}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/iccsense/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/iccsense/priv.h
index b72c31d2f908..e90e0f6ed008 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/iccsense/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/iccsense/priv.h
@@ -10,7 +10,7 @@ struct nvkm_iccsense_sensor {
10 enum nvbios_extdev_type type; 10 enum nvbios_extdev_type type;
11 struct i2c_adapter *i2c; 11 struct i2c_adapter *i2c;
12 u8 addr; 12 u8 addr;
13 u8 rail_mask; 13 u16 config;
14}; 14};
15 15
16struct nvkm_iccsense_rail { 16struct nvkm_iccsense_rail {
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/mxms.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/mxms.c
index 45a2f8e784f9..9abfa5e2fe9f 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/mxms.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/mxms.c
@@ -23,8 +23,8 @@
23 */ 23 */
24#include "mxms.h" 24#include "mxms.h"
25 25
26#define ROM16(x) le16_to_cpu(*(u16 *)&(x)) 26#define ROM16(x) get_unaligned_le16(&(x))
27#define ROM32(x) le32_to_cpu(*(u32 *)&(x)) 27#define ROM32(x) get_unaligned_le32(&(x))
28 28
29static u8 * 29static u8 *
30mxms_data(struct nvkm_mxm *mxm) 30mxms_data(struct nvkm_mxm *mxm)
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/Kbuild
index c34076223b7b..bcd179ba11d0 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/Kbuild
@@ -1,6 +1,7 @@
1nvkm-y += nvkm/subdev/volt/base.o 1nvkm-y += nvkm/subdev/volt/base.o
2nvkm-y += nvkm/subdev/volt/gpio.o 2nvkm-y += nvkm/subdev/volt/gpio.o
3nvkm-y += nvkm/subdev/volt/nv40.o 3nvkm-y += nvkm/subdev/volt/nv40.o
4nvkm-y += nvkm/subdev/volt/gf100.o
4nvkm-y += nvkm/subdev/volt/gk104.o 5nvkm-y += nvkm/subdev/volt/gk104.o
5nvkm-y += nvkm/subdev/volt/gk20a.o 6nvkm-y += nvkm/subdev/volt/gk20a.o
6nvkm-y += nvkm/subdev/volt/gm20b.o 7nvkm-y += nvkm/subdev/volt/gm20b.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c
index 1c3d23b0e84a..e8569b04b55d 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c
@@ -26,6 +26,7 @@
26#include <subdev/bios.h> 26#include <subdev/bios.h>
27#include <subdev/bios/vmap.h> 27#include <subdev/bios/vmap.h>
28#include <subdev/bios/volt.h> 28#include <subdev/bios/volt.h>
29#include <subdev/therm.h>
29 30
30int 31int
31nvkm_volt_get(struct nvkm_volt *volt) 32nvkm_volt_get(struct nvkm_volt *volt)
@@ -50,23 +51,35 @@ static int
50nvkm_volt_set(struct nvkm_volt *volt, u32 uv) 51nvkm_volt_set(struct nvkm_volt *volt, u32 uv)
51{ 52{
52 struct nvkm_subdev *subdev = &volt->subdev; 53 struct nvkm_subdev *subdev = &volt->subdev;
53 int i, ret = -EINVAL; 54 int i, ret = -EINVAL, best_err = volt->max_uv, best = -1;
54 55
55 if (volt->func->volt_set) 56 if (volt->func->volt_set)
56 return volt->func->volt_set(volt, uv); 57 return volt->func->volt_set(volt, uv);
57 58
58 for (i = 0; i < volt->vid_nr; i++) { 59 for (i = 0; i < volt->vid_nr; i++) {
59 if (volt->vid[i].uv == uv) { 60 int err = volt->vid[i].uv - uv;
60 ret = volt->func->vid_set(volt, volt->vid[i].vid); 61 if (err < 0 || err > best_err)
61 nvkm_debug(subdev, "set %duv: %d\n", uv, ret); 62 continue;
63
64 best_err = err;
65 best = i;
66 if (best_err == 0)
62 break; 67 break;
63 }
64 } 68 }
69
70 if (best == -1) {
71 nvkm_error(subdev, "couldn't set %iuv\n", uv);
72 return ret;
73 }
74
75 ret = volt->func->vid_set(volt, volt->vid[best].vid);
76 nvkm_debug(subdev, "set req %duv to %duv: %d\n", uv,
77 volt->vid[best].uv, ret);
65 return ret; 78 return ret;
66} 79}
67 80
68static int 81int
69nvkm_volt_map(struct nvkm_volt *volt, u8 id) 82nvkm_volt_map_min(struct nvkm_volt *volt, u8 id)
70{ 83{
71 struct nvkm_bios *bios = volt->subdev.device->bios; 84 struct nvkm_bios *bios = volt->subdev.device->bios;
72 struct nvbios_vmap_entry info; 85 struct nvbios_vmap_entry info;
@@ -76,7 +89,7 @@ nvkm_volt_map(struct nvkm_volt *volt, u8 id)
76 vmap = nvbios_vmap_entry_parse(bios, id, &ver, &len, &info); 89 vmap = nvbios_vmap_entry_parse(bios, id, &ver, &len, &info);
77 if (vmap) { 90 if (vmap) {
78 if (info.link != 0xff) { 91 if (info.link != 0xff) {
79 int ret = nvkm_volt_map(volt, info.link); 92 int ret = nvkm_volt_map_min(volt, info.link);
80 if (ret < 0) 93 if (ret < 0)
81 return ret; 94 return ret;
82 info.min += ret; 95 info.min += ret;
@@ -88,19 +101,79 @@ nvkm_volt_map(struct nvkm_volt *volt, u8 id)
88} 101}
89 102
90int 103int
91nvkm_volt_set_id(struct nvkm_volt *volt, u8 id, int condition) 104nvkm_volt_map(struct nvkm_volt *volt, u8 id, u8 temp)
105{
106 struct nvkm_bios *bios = volt->subdev.device->bios;
107 struct nvbios_vmap_entry info;
108 u8 ver, len;
109 u16 vmap;
110
111 vmap = nvbios_vmap_entry_parse(bios, id, &ver, &len, &info);
112 if (vmap) {
113 s64 result;
114
115 if (volt->speedo < 0)
116 return volt->speedo;
117
118 if (ver == 0x10 || (ver == 0x20 && info.mode == 0)) {
119 result = div64_s64((s64)info.arg[0], 10);
120 result += div64_s64((s64)info.arg[1] * volt->speedo, 10);
121 result += div64_s64((s64)info.arg[2] * volt->speedo * volt->speedo, 100000);
122 } else if (ver == 0x20) {
123 switch (info.mode) {
124 /* 0x0 handled above! */
125 case 0x1:
126 result = ((s64)info.arg[0] * 15625) >> 18;
127 result += ((s64)info.arg[1] * volt->speedo * 15625) >> 18;
128 result += ((s64)info.arg[2] * temp * 15625) >> 10;
129 result += ((s64)info.arg[3] * volt->speedo * temp * 15625) >> 18;
130 result += ((s64)info.arg[4] * volt->speedo * volt->speedo * 15625) >> 30;
131 result += ((s64)info.arg[5] * temp * temp * 15625) >> 18;
132 break;
133 case 0x3:
134 result = (info.min + info.max) / 2;
135 break;
136 case 0x2:
137 default:
138 result = info.min;
139 break;
140 }
141 } else {
142 return -ENODEV;
143 }
144
145 result = min(max(result, (s64)info.min), (s64)info.max);
146
147 if (info.link != 0xff) {
148 int ret = nvkm_volt_map(volt, info.link, temp);
149 if (ret < 0)
150 return ret;
151 result += ret;
152 }
153 return result;
154 }
155
156 return id ? id * 10000 : -ENODEV;
157}
158
159int
160nvkm_volt_set_id(struct nvkm_volt *volt, u8 id, u8 min_id, u8 temp,
161 int condition)
92{ 162{
93 int ret; 163 int ret;
94 164
95 if (volt->func->set_id) 165 if (volt->func->set_id)
96 return volt->func->set_id(volt, id, condition); 166 return volt->func->set_id(volt, id, condition);
97 167
98 ret = nvkm_volt_map(volt, id); 168 ret = nvkm_volt_map(volt, id, temp);
99 if (ret >= 0) { 169 if (ret >= 0) {
100 int prev = nvkm_volt_get(volt); 170 int prev = nvkm_volt_get(volt);
101 if (!condition || prev < 0 || 171 if (!condition || prev < 0 ||
102 (condition < 0 && ret < prev) || 172 (condition < 0 && ret < prev) ||
103 (condition > 0 && ret > prev)) { 173 (condition > 0 && ret > prev)) {
174 int min = nvkm_volt_map(volt, min_id, temp);
175 if (min >= 0)
176 ret = max(min, ret);
104 ret = nvkm_volt_set(volt, ret); 177 ret = nvkm_volt_set(volt, ret);
105 } else { 178 } else {
106 ret = 0; 179 ret = 0;
@@ -112,6 +185,7 @@ nvkm_volt_set_id(struct nvkm_volt *volt, u8 id, int condition)
112static void 185static void
113nvkm_volt_parse_bios(struct nvkm_bios *bios, struct nvkm_volt *volt) 186nvkm_volt_parse_bios(struct nvkm_bios *bios, struct nvkm_volt *volt)
114{ 187{
188 struct nvkm_subdev *subdev = &bios->subdev;
115 struct nvbios_volt_entry ivid; 189 struct nvbios_volt_entry ivid;
116 struct nvbios_volt info; 190 struct nvbios_volt info;
117 u8 ver, hdr, cnt, len; 191 u8 ver, hdr, cnt, len;
@@ -119,7 +193,8 @@ nvkm_volt_parse_bios(struct nvkm_bios *bios, struct nvkm_volt *volt)
119 int i; 193 int i;
120 194
121 data = nvbios_volt_parse(bios, &ver, &hdr, &cnt, &len, &info); 195 data = nvbios_volt_parse(bios, &ver, &hdr, &cnt, &len, &info);
122 if (data && info.vidmask && info.base && info.step) { 196 if (data && info.vidmask && info.base && info.step && info.ranged) {
197 nvkm_debug(subdev, "found ranged based VIDs\n");
123 volt->min_uv = info.min; 198 volt->min_uv = info.min;
124 volt->max_uv = info.max; 199 volt->max_uv = info.max;
125 for (i = 0; i < info.vidmask + 1; i++) { 200 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 info.base += info.step; 207 info.base += info.step;
133 } 208 }
134 volt->vid_mask = info.vidmask; 209 volt->vid_mask = info.vidmask;
135 } else if (data && info.vidmask) { 210 } else if (data && info.vidmask && !info.ranged) {
211 nvkm_debug(subdev, "found entry based VIDs\n");
136 volt->min_uv = 0xffffffff; 212 volt->min_uv = 0xffffffff;
137 volt->max_uv = 0; 213 volt->max_uv = 0;
138 for (i = 0; i < cnt; i++) { 214 for (i = 0; i < cnt; i++) {
@@ -154,6 +230,14 @@ nvkm_volt_parse_bios(struct nvkm_bios *bios, struct nvkm_volt *volt)
154} 230}
155 231
156static int 232static int
233nvkm_volt_speedo_read(struct nvkm_volt *volt)
234{
235 if (volt->func->speedo_read)
236 return volt->func->speedo_read(volt);
237 return -EINVAL;
238}
239
240static int
157nvkm_volt_init(struct nvkm_subdev *subdev) 241nvkm_volt_init(struct nvkm_subdev *subdev)
158{ 242{
159 struct nvkm_volt *volt = nvkm_volt(subdev); 243 struct nvkm_volt *volt = nvkm_volt(subdev);
@@ -167,6 +251,21 @@ nvkm_volt_init(struct nvkm_subdev *subdev)
167 return 0; 251 return 0;
168} 252}
169 253
254static int
255nvkm_volt_oneinit(struct nvkm_subdev *subdev)
256{
257 struct nvkm_volt *volt = nvkm_volt(subdev);
258
259 volt->speedo = nvkm_volt_speedo_read(volt);
260 if (volt->speedo > 0)
261 nvkm_debug(&volt->subdev, "speedo %x\n", volt->speedo);
262
263 if (volt->func->oneinit)
264 return volt->func->oneinit(volt);
265
266 return 0;
267}
268
170static void * 269static void *
171nvkm_volt_dtor(struct nvkm_subdev *subdev) 270nvkm_volt_dtor(struct nvkm_subdev *subdev)
172{ 271{
@@ -177,6 +276,7 @@ static const struct nvkm_subdev_func
177nvkm_volt = { 276nvkm_volt = {
178 .dtor = nvkm_volt_dtor, 277 .dtor = nvkm_volt_dtor,
179 .init = nvkm_volt_init, 278 .init = nvkm_volt_init,
279 .oneinit = nvkm_volt_oneinit,
180}; 280};
181 281
182void 282void
@@ -191,9 +291,22 @@ nvkm_volt_ctor(const struct nvkm_volt_func *func, struct nvkm_device *device,
191 291
192 /* Assuming the non-bios device should build the voltage table later */ 292 /* Assuming the non-bios device should build the voltage table later */
193 if (bios) { 293 if (bios) {
294 u8 ver, hdr, cnt, len;
295 struct nvbios_vmap vmap;
296
194 nvkm_volt_parse_bios(bios, volt); 297 nvkm_volt_parse_bios(bios, volt);
195 nvkm_debug(&volt->subdev, "min: %iuv max: %iuv\n", 298 nvkm_debug(&volt->subdev, "min: %iuv max: %iuv\n",
196 volt->min_uv, volt->max_uv); 299 volt->min_uv, volt->max_uv);
300
301 if (nvbios_vmap_parse(bios, &ver, &hdr, &cnt, &len, &vmap)) {
302 volt->max0_id = vmap.max0;
303 volt->max1_id = vmap.max1;
304 volt->max2_id = vmap.max2;
305 } else {
306 volt->max0_id = 0xff;
307 volt->max1_id = 0xff;
308 volt->max2_id = 0xff;
309 }
197 } 310 }
198 311
199 if (volt->vid_nr) { 312 if (volt->vid_nr) {
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gf100.c
new file mode 100644
index 000000000000..d9ed6925ca64
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gf100.c
@@ -0,0 +1,70 @@
1/*
2 * Copyright 2016 Karol Herbst
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Authors: Karol Herbst
23 */
24#include "priv.h"
25
26#include <subdev/fuse.h>
27
28static int
29gf100_volt_speedo_read(struct nvkm_volt *volt)
30{
31 struct nvkm_device *device = volt->subdev.device;
32 struct nvkm_fuse *fuse = device->fuse;
33
34 if (!fuse)
35 return -EINVAL;
36
37 return nvkm_fuse_read(fuse, 0x1cc);
38}
39
40int
41gf100_volt_oneinit(struct nvkm_volt *volt)
42{
43 struct nvkm_subdev *subdev = &volt->subdev;
44 if (volt->speedo <= 0)
45 nvkm_error(subdev, "couldn't find speedo value, volting not "
46 "possible\n");
47 return 0;
48}
49
50static const struct nvkm_volt_func
51gf100_volt = {
52 .oneinit = gf100_volt_oneinit,
53 .vid_get = nvkm_voltgpio_get,
54 .vid_set = nvkm_voltgpio_set,
55 .speedo_read = gf100_volt_speedo_read,
56};
57
58int
59gf100_volt_new(struct nvkm_device *device, int index, struct nvkm_volt **pvolt)
60{
61 struct nvkm_volt *volt;
62 int ret;
63
64 ret = nvkm_volt_new_(&gf100_volt, device, index, &volt);
65 *pvolt = volt;
66 if (ret)
67 return ret;
68
69 return nvkm_voltgpio_init(volt);
70}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk104.c
index 420bd84d8483..b2c5d1166a13 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk104.c
@@ -27,6 +27,7 @@
27#include <subdev/gpio.h> 27#include <subdev/gpio.h>
28#include <subdev/bios.h> 28#include <subdev/bios.h>
29#include <subdev/bios/volt.h> 29#include <subdev/bios/volt.h>
30#include <subdev/fuse.h>
30 31
31#define gk104_volt(p) container_of((p), struct gk104_volt, base) 32#define gk104_volt(p) container_of((p), struct gk104_volt, base)
32struct gk104_volt { 33struct gk104_volt {
@@ -64,13 +65,33 @@ gk104_volt_set(struct nvkm_volt *base, u32 uv)
64 return 0; 65 return 0;
65} 66}
66 67
68static int
69gk104_volt_speedo_read(struct nvkm_volt *volt)
70{
71 struct nvkm_device *device = volt->subdev.device;
72 struct nvkm_fuse *fuse = device->fuse;
73 int ret;
74
75 if (!fuse)
76 return -EINVAL;
77
78 nvkm_wr32(device, 0x122634, 0x0);
79 ret = nvkm_fuse_read(fuse, 0x3a8);
80 nvkm_wr32(device, 0x122634, 0x41);
81 return ret;
82}
83
67static const struct nvkm_volt_func 84static const struct nvkm_volt_func
68gk104_volt_pwm = { 85gk104_volt_pwm = {
86 .oneinit = gf100_volt_oneinit,
69 .volt_get = gk104_volt_get, 87 .volt_get = gk104_volt_get,
70 .volt_set = gk104_volt_set, 88 .volt_set = gk104_volt_set,
89 .speedo_read = gk104_volt_speedo_read,
71}, gk104_volt_gpio = { 90}, gk104_volt_gpio = {
91 .oneinit = gf100_volt_oneinit,
72 .vid_get = nvkm_voltgpio_get, 92 .vid_get = nvkm_voltgpio_get,
73 .vid_set = nvkm_voltgpio_set, 93 .vid_set = nvkm_voltgpio_set,
94 .speedo_read = gk104_volt_speedo_read,
74}; 95};
75 96
76int 97int
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/priv.h
index d5140d991161..354bafe4b4e2 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/priv.h
@@ -9,11 +9,13 @@ int nvkm_volt_new_(const struct nvkm_volt_func *, struct nvkm_device *,
9 int index, struct nvkm_volt **); 9 int index, struct nvkm_volt **);
10 10
11struct nvkm_volt_func { 11struct nvkm_volt_func {
12 int (*oneinit)(struct nvkm_volt *);
12 int (*volt_get)(struct nvkm_volt *); 13 int (*volt_get)(struct nvkm_volt *);
13 int (*volt_set)(struct nvkm_volt *, u32 uv); 14 int (*volt_set)(struct nvkm_volt *, u32 uv);
14 int (*vid_get)(struct nvkm_volt *); 15 int (*vid_get)(struct nvkm_volt *);
15 int (*vid_set)(struct nvkm_volt *, u8 vid); 16 int (*vid_set)(struct nvkm_volt *, u8 vid);
16 int (*set_id)(struct nvkm_volt *, u8 id, int condition); 17 int (*set_id)(struct nvkm_volt *, u8 id, int condition);
18 int (*speedo_read)(struct nvkm_volt *);
17}; 19};
18 20
19int nvkm_voltgpio_init(struct nvkm_volt *); 21int nvkm_voltgpio_init(struct nvkm_volt *);
@@ -23,4 +25,6 @@ int nvkm_voltgpio_set(struct nvkm_volt *, u8);
23int nvkm_voltpwm_init(struct nvkm_volt *volt); 25int nvkm_voltpwm_init(struct nvkm_volt *volt);
24int nvkm_voltpwm_get(struct nvkm_volt *volt); 26int nvkm_voltpwm_get(struct nvkm_volt *volt);
25int nvkm_voltpwm_set(struct nvkm_volt *volt, u32 uv); 27int nvkm_voltpwm_set(struct nvkm_volt *volt, u32 uv);
28
29int gf100_volt_oneinit(struct nvkm_volt *);
26#endif 30#endif