Skip to content

Commit

Permalink
Merge branch 'linux-4.9' of git://github.com/skeggsb/linux into drm-next
Browse files Browse the repository at this point in the history
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
  ...
  • Loading branch information
Dave Airlie committed Oct 28, 2016
2 parents 220196b + 2ecf7c4 commit fb42295
Show file tree
Hide file tree
Showing 44 changed files with 904 additions and 207 deletions.
1 change: 1 addition & 0 deletions drivers/gpu/drm/nouveau/Kbuild
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ nouveau-$(CONFIG_DEBUG_FS) += nouveau_debugfs.o
nouveau-y += nouveau_drm.o
nouveau-y += nouveau_hwmon.o
nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o
nouveau-$(CONFIG_LEDS_CLASS) += nouveau_led.o
nouveau-y += nouveau_nvif.o
nouveau-$(CONFIG_NOUVEAU_PLATFORM_DRIVER) += nouveau_platform.o
nouveau-y += nouveau_usif.o # userspace <-> nvif
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/gpio.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ enum dcb_gpio_func_name {
DCB_GPIO_TVDAC1 = 0x2d,
DCB_GPIO_FAN = 0x09,
DCB_GPIO_FAN_SENSE = 0x3d,
DCB_GPIO_LOGO_LED_PWM = 0x84,
DCB_GPIO_UNUSED = 0xff,
DCB_GPIO_VID0 = 0x04,
DCB_GPIO_VID1 = 0x05,
Expand Down
10 changes: 8 additions & 2 deletions drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/iccsense.h
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
#ifndef __NVBIOS_ICCSENSE_H__
#define __NVBIOS_ICCSENSE_H__
struct pwr_rail_resistor_t {
u8 mohm;
bool enabled;
};

struct pwr_rail_t {
u8 mode;
u8 extdev_id;
u8 resistor_mohm;
u8 rail;
u8 resistor_count;
struct pwr_rail_resistor_t resistors[3];
u16 config;
};

struct nvbios_iccsense {
Expand Down
5 changes: 4 additions & 1 deletion drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/vmap.h
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
#ifndef __NVBIOS_VMAP_H__
#define __NVBIOS_VMAP_H__
struct nvbios_vmap {
u8 max0;
u8 max1;
u8 max2;
};

u16 nvbios_vmap_table(struct nvkm_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
u16 nvbios_vmap_parse(struct nvkm_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
struct nvbios_vmap *);

struct nvbios_vmap_entry {
u8 unk0;
u8 mode;
u8 link;
u32 min;
u32 max;
Expand Down
5 changes: 3 additions & 2 deletions drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/volt.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ struct nvbios_volt {
u32 base;

/* GPIO mode */
u8 vidmask;
s16 step;
bool ranged;
u8 vidmask;
s16 step;

/* PWM mode */
u32 pwm_freq;
Expand Down
24 changes: 24 additions & 0 deletions drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/vpstate.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#ifndef __NVBIOS_VPSTATE_H__
#define __NVBIOS_VPSTATE_H__
struct nvbios_vpstate_header {
u32 offset;

u8 version;
u8 hlen;
u8 ecount;
u8 elen;
u8 scount;
u8 slen;

u8 base_id;
u8 boost_id;
u8 tdp_id;
};
struct nvbios_vpstate_entry {
u8 pstate;
u16 clock_mhz;
};
int nvbios_vpstate_parse(struct nvkm_bios *, struct nvbios_vpstate_header *);
int nvbios_vpstate_entry(struct nvkm_bios *, struct nvbios_vpstate_header *,
u8 idx, struct nvbios_vpstate_entry *);
#endif
18 changes: 15 additions & 3 deletions drivers/gpu/drm/nouveau/include/nvkm/subdev/clk.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
struct nvbios_pll;
struct nvkm_pll_vals;

#define NVKM_CLK_CSTATE_DEFAULT -1 /* POSTed default */
#define NVKM_CLK_CSTATE_BASE -2 /* pstate base */
#define NVKM_CLK_CSTATE_HIGHEST -3 /* highest possible */

enum nv_clk_src {
nv_clk_src_crystal,
nv_clk_src_href,
Expand Down Expand Up @@ -52,6 +56,7 @@ struct nvkm_cstate {
struct list_head head;
u8 voltage;
u32 domain[nv_clk_src_max];
u8 id;
};

struct nvkm_pstate {
Expand All @@ -67,7 +72,8 @@ struct nvkm_pstate {
struct nvkm_domain {
enum nv_clk_src name;
u8 bios; /* 0xff for none */
#define NVKM_CLK_DOM_FLAG_CORE 0x01
#define NVKM_CLK_DOM_FLAG_CORE 0x01
#define NVKM_CLK_DOM_FLAG_VPSTATE 0x02
u8 flags;
const char *mname;
int mdiv;
Expand All @@ -93,10 +99,16 @@ struct nvkm_clk {
int ustate_ac; /* user-requested (-1 disabled, -2 perfmon) */
int ustate_dc; /* user-requested (-1 disabled, -2 perfmon) */
int astate; /* perfmon adjustment (base) */
int tstate; /* thermal adjustment (max-) */
int dstate; /* display adjustment (min+) */
u8 temp;

bool allow_reclock;
#define NVKM_CLK_BOOST_NONE 0x0
#define NVKM_CLK_BOOST_BIOS 0x1
#define NVKM_CLK_BOOST_FULL 0x2
u8 boost_mode;
u32 base_khz;
u32 boost_khz;

/*XXX: die, these are here *only* to support the completely
* bat-shit insane what-was-nouveau_hw.c code
Expand All @@ -110,7 +122,7 @@ int nvkm_clk_read(struct nvkm_clk *, enum nv_clk_src);
int nvkm_clk_ustate(struct nvkm_clk *, int req, int pwr);
int nvkm_clk_astate(struct nvkm_clk *, int req, int rel, bool wait);
int nvkm_clk_dstate(struct nvkm_clk *, int req, int rel);
int nvkm_clk_tstate(struct nvkm_clk *, int req, int rel);
int nvkm_clk_tstate(struct nvkm_clk *, u8 temperature);

int nv04_clk_new(struct nvkm_device *, int, struct nvkm_clk **);
int nv40_clk_new(struct nvkm_device *, int, struct nvkm_clk **);
Expand Down
18 changes: 17 additions & 1 deletion drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,28 @@ struct nvkm_volt {

u32 max_uv;
u32 min_uv;

/*
* These are fully functional map entries creating a sw ceiling for
* the voltage. These all can describe different kind of curves, so
* that for any given temperature a different one can return the lowest
* value of all three.
*/
u8 max0_id;
u8 max1_id;
u8 max2_id;

int speedo;
};

int nvkm_volt_map(struct nvkm_volt *volt, u8 id, u8 temperature);
int nvkm_volt_map_min(struct nvkm_volt *volt, u8 id);
int nvkm_volt_get(struct nvkm_volt *);
int nvkm_volt_set_id(struct nvkm_volt *, u8 id, int condition);
int nvkm_volt_set_id(struct nvkm_volt *, u8 id, u8 min_id, u8 temp,
int condition);

int nv40_volt_new(struct nvkm_device *, int, struct nvkm_volt **);
int gf100_volt_new(struct nvkm_device *, int, struct nvkm_volt **);
int gk104_volt_new(struct nvkm_device *, int, struct nvkm_volt **);
int gk20a_volt_new(struct nvkm_device *, int, struct nvkm_volt **);
int gm20b_volt_new(struct nvkm_device *, int, struct nvkm_volt **);
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/nouveau/nouveau_backlight.c
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ nouveau_backlight_init(struct drm_device *dev)
case NV_DEVICE_INFO_V0_TESLA:
case NV_DEVICE_INFO_V0_FERMI:
case NV_DEVICE_INFO_V0_KEPLER:
case NV_DEVICE_INFO_V0_MAXWELL:
return nv50_backlight_init(connector);
default:
break;
Expand Down
6 changes: 2 additions & 4 deletions drivers/gpu/drm/nouveau/nouveau_bios.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,8 @@

#define DCB_LOC_ON_CHIP 0

#define ROM16(x) le16_to_cpu(*(u16 *)&(x))
#define ROM32(x) le32_to_cpu(*(u32 *)&(x))
#define ROM48(x) ({ u8 *p = &(x); (u64)ROM16(p[4]) << 32 | ROM32(p[0]); })
#define ROM64(x) le64_to_cpu(*(u64 *)&(x))
#define ROM16(x) get_unaligned_le16(&(x))
#define ROM32(x) get_unaligned_le32(&(x))
#define ROMPTR(d,x) ({ \
struct nouveau_drm *drm = nouveau_drm((d)); \
ROM16(x) ? &drm->vbios.data[ROM16(x)] : NULL; \
Expand Down
7 changes: 7 additions & 0 deletions drivers/gpu/drm/nouveau/nouveau_drm.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
#include "nouveau_ttm.h"
#include "nouveau_gem.h"
#include "nouveau_vga.h"
#include "nouveau_led.h"
#include "nouveau_hwmon.h"
#include "nouveau_acpi.h"
#include "nouveau_bios.h"
Expand Down Expand Up @@ -475,6 +476,7 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags)
nouveau_hwmon_init(dev);
nouveau_accel_init(drm);
nouveau_fbcon_init(dev);
nouveau_led_init(dev);

if (nouveau_runtime_pm != 0) {
pm_runtime_use_autosuspend(dev->dev);
Expand Down Expand Up @@ -510,6 +512,7 @@ nouveau_drm_unload(struct drm_device *dev)
pm_runtime_forbid(dev->dev);
}

nouveau_led_fini(dev);
nouveau_fbcon_fini(dev);
nouveau_accel_fini(drm);
nouveau_hwmon_fini(dev);
Expand Down Expand Up @@ -561,6 +564,8 @@ nouveau_do_suspend(struct drm_device *dev, bool runtime)
struct nouveau_cli *cli;
int ret;

nouveau_led_suspend(dev);

if (dev->mode_config.num_crtc) {
NV_INFO(drm, "suspending console...\n");
nouveau_fbcon_set_suspend(dev, 1);
Expand Down Expand Up @@ -649,6 +654,8 @@ nouveau_do_resume(struct drm_device *dev, bool runtime)
nouveau_fbcon_set_suspend(dev, 0);
}

nouveau_led_resume(dev);

return 0;
}

Expand Down
3 changes: 3 additions & 0 deletions drivers/gpu/drm/nouveau/nouveau_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,9 @@ struct nouveau_drm {
struct nouveau_hwmon *hwmon;
struct nouveau_debugfs *debugfs;

/* led management */
struct nouveau_led *led;

/* display power reference */
bool have_disp_power_ref;

Expand Down
139 changes: 139 additions & 0 deletions drivers/gpu/drm/nouveau/nouveau_led.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/*
* Copyright (C) 2016 Martin Peres
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/

/*
* Authors:
* Martin Peres <martin.peres@free.fr>
*/

#include <linux/leds.h>

#include "nouveau_led.h"
#include <nvkm/subdev/gpio.h>

static enum led_brightness
nouveau_led_get_brightness(struct led_classdev *led)
{
struct drm_device *drm_dev = container_of(led, struct nouveau_led, led)->dev;
struct nouveau_drm *drm = nouveau_drm(drm_dev);
struct nvif_object *device = &drm->device.object;
u32 div, duty;

div = nvif_rd32(device, 0x61c880) & 0x00ffffff;
duty = nvif_rd32(device, 0x61c884) & 0x00ffffff;

if (div > 0)
return duty * LED_FULL / div;
else
return 0;
}

static void
nouveau_led_set_brightness(struct led_classdev *led, enum led_brightness value)
{
struct drm_device *drm_dev = container_of(led, struct nouveau_led, led)->dev;
struct nouveau_drm *drm = nouveau_drm(drm_dev);
struct nvif_object *device = &drm->device.object;

u32 input_clk = 27e6; /* PDISPLAY.SOR[1].PWM is connected to the crystal */
u32 freq = 100; /* this is what nvidia uses and it should be good-enough */
u32 div, duty;

div = input_clk / freq;
duty = value * div / LED_FULL;

/* for now, this is safe to directly poke those registers because:
* - A: nvidia never puts the logo led to any other PWM controler
* than PDISPLAY.SOR[1].PWM.
* - B: nouveau does not touch these registers anywhere else
*/
nvif_wr32(device, 0x61c880, div);
nvif_wr32(device, 0x61c884, 0xc0000000 | duty);
}


int
nouveau_led_init(struct drm_device *dev)
{
struct nouveau_drm *drm = nouveau_drm(dev);
struct nvkm_gpio *gpio = nvxx_gpio(&drm->device);
struct dcb_gpio_func logo_led;
int ret;

if (!gpio)
return 0;

/* check that there is a GPIO controlling the logo LED */
if (nvkm_gpio_find(gpio, 0, DCB_GPIO_LOGO_LED_PWM, 0xff, &logo_led))
return 0;

drm->led = kzalloc(sizeof(*drm->led), GFP_KERNEL);
if (!drm->led)
return -ENOMEM;
drm->led->dev = dev;

drm->led->led.name = "nvidia-logo";
drm->led->led.max_brightness = 255;
drm->led->led.brightness_get = nouveau_led_get_brightness;
drm->led->led.brightness_set = nouveau_led_set_brightness;

ret = led_classdev_register(dev->dev, &drm->led->led);
if (ret) {
kfree(drm->led);
return ret;
}

return 0;
}

void
nouveau_led_suspend(struct drm_device *dev)
{
struct nouveau_drm *drm = nouveau_drm(dev);

if (drm->led)
led_classdev_suspend(&drm->led->led);
}

void
nouveau_led_resume(struct drm_device *dev)
{
struct nouveau_drm *drm = nouveau_drm(dev);

if (drm->led)
led_classdev_resume(&drm->led->led);
}

void
nouveau_led_fini(struct drm_device *dev)
{
struct nouveau_drm *drm = nouveau_drm(dev);

if (drm->led) {
led_classdev_unregister(&drm->led->led);
kfree(drm->led);
drm->led = NULL;
}
}
Loading

0 comments on commit fb42295

Please sign in to comment.