Commit fb422950 authored by Dave Airlie's avatar Dave Airlie
Browse files

Merge branch 'linux-4.9' of git://github.com/skeggsb/linux into drm-next

Karol's work which greatly improves volt/clock changes on a
heap of boards, nothing too exciting beyond a random collection of fixes.

* 'linux-4.9' of git://github.com/skeggsb/linux: (33 commits)
  drm/nouveau/fb/nv50: defer DMA mapping of scratch page to oneinit() hook
  drm/nouveau/fb/gf100: defer DMA mapping of scratch page to oneinit() hook
  drm/nouveau/pci: set streaming DMA mask early
  drm/nouveau/kms: add Maxwell to backlight initialization
  drm/nouveau/bar/nv50: fix bar2 vm size
  drm/nouveau/disp: remove unused function in sorg94.c
  drm/nouveau/volt: use kernel's 64-bit signed division function
  drm/nouveau/core: add missing header dependencies
  drm/nouveau/gr/nv3x: add 0x0597 kelvin 3d class support
  drm/nouveau/drm/nouveau: add a LED driver for the NVIDIA logo
  drm/nouveau/fb/ram: Use Kepler implementation on Maxwell
  drm/nouveau/volt: Make use of cvb coefficients
  drm/nouveau/volt/gf100-: Add speedo
  drm/nouveau/volt: Add implementation for gf100
  drm/nouveau/bios/vmap: unk0 field is the mode
  drm/nouveau/volt: Don't require perfect fit
  drm/nouveau/clk: Allow boosting only when NvBoost is set
  drm/nouveau/bios: Add parsing of VPSTATE table
  drm/nouveau/clk: Respect voltage limits in nvkm_cstate_prog
  drm/nouveau/clk: Fixup cstate selection
  ...
parents 220196b3 2ecf7c43
No related merge requests found
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <subdev/bios.h> #include <subdev/bios.h>
#include <subdev/bios/vmap.h> #include <subdev/bios/vmap.h>
#include <subdev/bios/volt.h> #include <subdev/bios/volt.h>
#include <subdev/therm.h>
int int
nvkm_volt_get(struct nvkm_volt *volt) nvkm_volt_get(struct nvkm_volt *volt)
...@@ -50,23 +51,35 @@ static int ...@@ -50,23 +51,35 @@ static int
nvkm_volt_set(struct nvkm_volt *volt, u32 uv) nvkm_volt_set(struct nvkm_volt *volt, u32 uv)
{ {
struct nvkm_subdev *subdev = &volt->subdev; struct nvkm_subdev *subdev = &volt->subdev;
int i, ret = -EINVAL; int i, ret = -EINVAL, best_err = volt->max_uv, best = -1;
if (volt->func->volt_set) if (volt->func->volt_set)
return volt->func->volt_set(volt, uv); return volt->func->volt_set(volt, uv);
for (i = 0; i < volt->vid_nr; i++) { for (i = 0; i < volt->vid_nr; i++) {
if (volt->vid[i].uv == uv) { int err = volt->vid[i].uv - uv;
ret = volt->func->vid_set(volt, volt->vid[i].vid); if (err < 0 || err > best_err)
nvkm_debug(subdev, "set %duv: %d\n", uv, ret); continue;
best_err = err;
best = i;
if (best_err == 0)
break; break;
}
} }
if (best == -1) {
nvkm_error(subdev, "couldn't set %iuv\n", uv);
return ret;
}
ret = volt->func->vid_set(volt, volt->vid[best].vid);
nvkm_debug(subdev, "set req %duv to %duv: %d\n", uv,
volt->vid[best].uv, ret);
return ret; return ret;
} }
static int int
nvkm_volt_map(struct nvkm_volt *volt, u8 id) nvkm_volt_map_min(struct nvkm_volt *volt, u8 id)
{ {
struct nvkm_bios *bios = volt->subdev.device->bios; struct nvkm_bios *bios = volt->subdev.device->bios;
struct nvbios_vmap_entry info; struct nvbios_vmap_entry info;
...@@ -76,7 +89,7 @@ nvkm_volt_map(struct nvkm_volt *volt, u8 id) ...@@ -76,7 +89,7 @@ nvkm_volt_map(struct nvkm_volt *volt, u8 id)
vmap = nvbios_vmap_entry_parse(bios, id, &ver, &len, &info); vmap = nvbios_vmap_entry_parse(bios, id, &ver, &len, &info);
if (vmap) { if (vmap) {
if (info.link != 0xff) { if (info.link != 0xff) {
int ret = nvkm_volt_map(volt, info.link); int ret = nvkm_volt_map_min(volt, info.link);
if (ret < 0) if (ret < 0)
return ret; return ret;
info.min += ret; info.min += ret;
...@@ -88,19 +101,79 @@ nvkm_volt_map(struct nvkm_volt *volt, u8 id) ...@@ -88,19 +101,79 @@ nvkm_volt_map(struct nvkm_volt *volt, u8 id)
} }
int int
nvkm_volt_set_id(struct nvkm_volt *volt, u8 id, int condition) nvkm_volt_map(struct nvkm_volt *volt, u8 id, u8 temp)
{
struct nvkm_bios *bios = volt->subdev.device->bios;
struct nvbios_vmap_entry info;
u8 ver, len;
u16 vmap;
vmap = nvbios_vmap_entry_parse(bios, id, &ver, &len, &info);
if (vmap) {
s64 result;
if (volt->speedo < 0)
return volt->speedo;
if (ver == 0x10 || (ver == 0x20 && info.mode == 0)) {
result = div64_s64((s64)info.arg[0], 10);
result += div64_s64((s64)info.arg[1] * volt->speedo, 10);
result += div64_s64((s64)info.arg[2] * volt->speedo * volt->speedo, 100000);
} else if (ver == 0x20) {
switch (info.mode) {
/* 0x0 handled above! */
case 0x1:
result = ((s64)info.arg[0] * 15625) >> 18;
result += ((s64)info.arg[1] * volt->speedo * 15625) >> 18;
result += ((s64)info.arg[2] * temp * 15625) >> 10;
result += ((s64)info.arg[3] * volt->speedo * temp * 15625) >> 18;
result += ((s64)info.arg[4] * volt->speedo * volt->speedo * 15625) >> 30;
result += ((s64)info.arg[5] * temp * temp * 15625) >> 18;
break;
case 0x3:
result = (info.min + info.max) / 2;
break;
case 0x2:
default:
result = info.min;
break;
}
} else {
return -ENODEV;
}
result = min(max(result, (s64)info.min), (s64)info.max);
if (info.link != 0xff) {
int ret = nvkm_volt_map(volt, info.link, temp);
if (ret < 0)
return ret;
result += ret;
}
return result;
}
return id ? id * 10000 : -ENODEV;
}
int
nvkm_volt_set_id(struct nvkm_volt *volt, u8 id, u8 min_id, u8 temp,
int condition)
{ {
int ret; int ret;
if (volt->func->set_id) if (volt->func->set_id)
return volt->func->set_id(volt, id, condition); return volt->func->set_id(volt, id, condition);
ret = nvkm_volt_map(volt, id); ret = nvkm_volt_map(volt, id, temp);
if (ret >= 0) { if (ret >= 0) {
int prev = nvkm_volt_get(volt); int prev = nvkm_volt_get(volt);
if (!condition || prev < 0 || if (!condition || prev < 0 ||
(condition < 0 && ret < prev) || (condition < 0 && ret < prev) ||
(condition > 0 && ret > prev)) { (condition > 0 && ret > prev)) {
int min = nvkm_volt_map(volt, min_id, temp);
if (min >= 0)
ret = max(min, ret);
ret = nvkm_volt_set(volt, ret); ret = nvkm_volt_set(volt, ret);
} else { } else {
ret = 0; ret = 0;
...@@ -112,6 +185,7 @@ nvkm_volt_set_id(struct nvkm_volt *volt, u8 id, int condition) ...@@ -112,6 +185,7 @@ nvkm_volt_set_id(struct nvkm_volt *volt, u8 id, int condition)
static void static void
nvkm_volt_parse_bios(struct nvkm_bios *bios, struct nvkm_volt *volt) nvkm_volt_parse_bios(struct nvkm_bios *bios, struct nvkm_volt *volt)
{ {
struct nvkm_subdev *subdev = &bios->subdev;
struct nvbios_volt_entry ivid; struct nvbios_volt_entry ivid;
struct nvbios_volt info; struct nvbios_volt info;
u8 ver, hdr, cnt, len; u8 ver, hdr, cnt, len;
...@@ -119,7 +193,8 @@ nvkm_volt_parse_bios(struct nvkm_bios *bios, struct nvkm_volt *volt) ...@@ -119,7 +193,8 @@ nvkm_volt_parse_bios(struct nvkm_bios *bios, struct nvkm_volt *volt)
int i; int i;
data = nvbios_volt_parse(bios, &ver, &hdr, &cnt, &len, &info); data = nvbios_volt_parse(bios, &ver, &hdr, &cnt, &len, &info);
if (data && info.vidmask && info.base && info.step) { if (data && info.vidmask && info.base && info.step && info.ranged) {
nvkm_debug(subdev, "found ranged based VIDs\n");
volt->min_uv = info.min; volt->min_uv = info.min;
volt->max_uv = info.max; volt->max_uv = info.max;
for (i = 0; i < info.vidmask + 1; i++) { for (i = 0; i < info.vidmask + 1; i++) {
...@@ -132,7 +207,8 @@ nvkm_volt_parse_bios(struct nvkm_bios *bios, struct nvkm_volt *volt) ...@@ -132,7 +207,8 @@ nvkm_volt_parse_bios(struct nvkm_bios *bios, struct nvkm_volt *volt)
info.base += info.step; info.base += info.step;
} }
volt->vid_mask = info.vidmask; volt->vid_mask = info.vidmask;
} else if (data && info.vidmask) { } else if (data && info.vidmask && !info.ranged) {
nvkm_debug(subdev, "found entry based VIDs\n");
volt->min_uv = 0xffffffff; volt->min_uv = 0xffffffff;
volt->max_uv = 0; volt->max_uv = 0;
for (i = 0; i < cnt; i++) { for (i = 0; i < cnt; i++) {
...@@ -153,6 +229,14 @@ nvkm_volt_parse_bios(struct nvkm_bios *bios, struct nvkm_volt *volt) ...@@ -153,6 +229,14 @@ nvkm_volt_parse_bios(struct nvkm_bios *bios, struct nvkm_volt *volt)
} }
} }
static int
nvkm_volt_speedo_read(struct nvkm_volt *volt)
{
if (volt->func->speedo_read)
return volt->func->speedo_read(volt);
return -EINVAL;
}
static int static int
nvkm_volt_init(struct nvkm_subdev *subdev) nvkm_volt_init(struct nvkm_subdev *subdev)
{ {
...@@ -167,6 +251,21 @@ nvkm_volt_init(struct nvkm_subdev *subdev) ...@@ -167,6 +251,21 @@ nvkm_volt_init(struct nvkm_subdev *subdev)
return 0; return 0;
} }
static int
nvkm_volt_oneinit(struct nvkm_subdev *subdev)
{
struct nvkm_volt *volt = nvkm_volt(subdev);
volt->speedo = nvkm_volt_speedo_read(volt);
if (volt->speedo > 0)
nvkm_debug(&volt->subdev, "speedo %x\n", volt->speedo);
if (volt->func->oneinit)
return volt->func->oneinit(volt);
return 0;
}
static void * static void *
nvkm_volt_dtor(struct nvkm_subdev *subdev) nvkm_volt_dtor(struct nvkm_subdev *subdev)
{ {
...@@ -177,6 +276,7 @@ static const struct nvkm_subdev_func ...@@ -177,6 +276,7 @@ static const struct nvkm_subdev_func
nvkm_volt = { nvkm_volt = {
.dtor = nvkm_volt_dtor, .dtor = nvkm_volt_dtor,
.init = nvkm_volt_init, .init = nvkm_volt_init,
.oneinit = nvkm_volt_oneinit,
}; };
void void
...@@ -191,9 +291,22 @@ nvkm_volt_ctor(const struct nvkm_volt_func *func, struct nvkm_device *device, ...@@ -191,9 +291,22 @@ nvkm_volt_ctor(const struct nvkm_volt_func *func, struct nvkm_device *device,
/* Assuming the non-bios device should build the voltage table later */ /* Assuming the non-bios device should build the voltage table later */
if (bios) { if (bios) {
u8 ver, hdr, cnt, len;
struct nvbios_vmap vmap;
nvkm_volt_parse_bios(bios, volt); nvkm_volt_parse_bios(bios, volt);
nvkm_debug(&volt->subdev, "min: %iuv max: %iuv\n", nvkm_debug(&volt->subdev, "min: %iuv max: %iuv\n",
volt->min_uv, volt->max_uv); volt->min_uv, volt->max_uv);
if (nvbios_vmap_parse(bios, &ver, &hdr, &cnt, &len, &vmap)) {
volt->max0_id = vmap.max0;
volt->max1_id = vmap.max1;
volt->max2_id = vmap.max2;
} else {
volt->max0_id = 0xff;
volt->max1_id = 0xff;
volt->max2_id = 0xff;
}
} }
if (volt->vid_nr) { if (volt->vid_nr) {
......
/*
* Copyright 2016 Karol Herbst
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Karol Herbst
*/
#include "priv.h"
#include <subdev/fuse.h>
static int
gf100_volt_speedo_read(struct nvkm_volt *volt)
{
struct nvkm_device *device = volt->subdev.device;
struct nvkm_fuse *fuse = device->fuse;
if (!fuse)
return -EINVAL;
return nvkm_fuse_read(fuse, 0x1cc);
}
int
gf100_volt_oneinit(struct nvkm_volt *volt)
{
struct nvkm_subdev *subdev = &volt->subdev;
if (volt->speedo <= 0)
nvkm_error(subdev, "couldn't find speedo value, volting not "
"possible\n");
return 0;
}
static const struct nvkm_volt_func
gf100_volt = {
.oneinit = gf100_volt_oneinit,
.vid_get = nvkm_voltgpio_get,
.vid_set = nvkm_voltgpio_set,
.speedo_read = gf100_volt_speedo_read,
};
int
gf100_volt_new(struct nvkm_device *device, int index, struct nvkm_volt **pvolt)
{
struct nvkm_volt *volt;
int ret;
ret = nvkm_volt_new_(&gf100_volt, device, index, &volt);
*pvolt = volt;
if (ret)
return ret;
return nvkm_voltgpio_init(volt);
}
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <subdev/gpio.h> #include <subdev/gpio.h>
#include <subdev/bios.h> #include <subdev/bios.h>
#include <subdev/bios/volt.h> #include <subdev/bios/volt.h>
#include <subdev/fuse.h>
#define gk104_volt(p) container_of((p), struct gk104_volt, base) #define gk104_volt(p) container_of((p), struct gk104_volt, base)
struct gk104_volt { struct gk104_volt {
...@@ -64,13 +65,33 @@ gk104_volt_set(struct nvkm_volt *base, u32 uv) ...@@ -64,13 +65,33 @@ gk104_volt_set(struct nvkm_volt *base, u32 uv)
return 0; return 0;
} }
static int
gk104_volt_speedo_read(struct nvkm_volt *volt)
{
struct nvkm_device *device = volt->subdev.device;
struct nvkm_fuse *fuse = device->fuse;
int ret;
if (!fuse)
return -EINVAL;
nvkm_wr32(device, 0x122634, 0x0);
ret = nvkm_fuse_read(fuse, 0x3a8);
nvkm_wr32(device, 0x122634, 0x41);
return ret;
}
static const struct nvkm_volt_func static const struct nvkm_volt_func
gk104_volt_pwm = { gk104_volt_pwm = {
.oneinit = gf100_volt_oneinit,
.volt_get = gk104_volt_get, .volt_get = gk104_volt_get,
.volt_set = gk104_volt_set, .volt_set = gk104_volt_set,
.speedo_read = gk104_volt_speedo_read,
}, gk104_volt_gpio = { }, gk104_volt_gpio = {
.oneinit = gf100_volt_oneinit,
.vid_get = nvkm_voltgpio_get, .vid_get = nvkm_voltgpio_get,
.vid_set = nvkm_voltgpio_set, .vid_set = nvkm_voltgpio_set,
.speedo_read = gk104_volt_speedo_read,
}; };
int int
......
...@@ -9,11 +9,13 @@ int nvkm_volt_new_(const struct nvkm_volt_func *, struct nvkm_device *, ...@@ -9,11 +9,13 @@ int nvkm_volt_new_(const struct nvkm_volt_func *, struct nvkm_device *,
int index, struct nvkm_volt **); int index, struct nvkm_volt **);
struct nvkm_volt_func { struct nvkm_volt_func {
int (*oneinit)(struct nvkm_volt *);
int (*volt_get)(struct nvkm_volt *); int (*volt_get)(struct nvkm_volt *);
int (*volt_set)(struct nvkm_volt *, u32 uv); int (*volt_set)(struct nvkm_volt *, u32 uv);
int (*vid_get)(struct nvkm_volt *); int (*vid_get)(struct nvkm_volt *);
int (*vid_set)(struct nvkm_volt *, u8 vid); int (*vid_set)(struct nvkm_volt *, u8 vid);
int (*set_id)(struct nvkm_volt *, u8 id, int condition); int (*set_id)(struct nvkm_volt *, u8 id, int condition);
int (*speedo_read)(struct nvkm_volt *);
}; };
int nvkm_voltgpio_init(struct nvkm_volt *); int nvkm_voltgpio_init(struct nvkm_volt *);
...@@ -23,4 +25,6 @@ int nvkm_voltgpio_set(struct nvkm_volt *, u8); ...@@ -23,4 +25,6 @@ int nvkm_voltgpio_set(struct nvkm_volt *, u8);
int nvkm_voltpwm_init(struct nvkm_volt *volt); int nvkm_voltpwm_init(struct nvkm_volt *volt);
int nvkm_voltpwm_get(struct nvkm_volt *volt); int nvkm_voltpwm_get(struct nvkm_volt *volt);
int nvkm_voltpwm_set(struct nvkm_volt *volt, u32 uv); int nvkm_voltpwm_set(struct nvkm_volt *volt, u32 uv);
int gf100_volt_oneinit(struct nvkm_volt *);
#endif #endif
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment