diff options
Diffstat (limited to 'drivers')
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 | |||
| 22 | nouveau-y += nouveau_drm.o | 22 | nouveau-y += nouveau_drm.o |
| 23 | nouveau-y += nouveau_hwmon.o | 23 | nouveau-y += nouveau_hwmon.o |
| 24 | nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o | 24 | nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o |
| 25 | nouveau-$(CONFIG_LEDS_CLASS) += nouveau_led.o | ||
| 25 | nouveau-y += nouveau_nvif.o | 26 | nouveau-y += nouveau_nvif.o |
| 26 | nouveau-$(CONFIG_NOUVEAU_PLATFORM_DRIVER) += nouveau_platform.o | 27 | nouveau-$(CONFIG_NOUVEAU_PLATFORM_DRIVER) += nouveau_platform.o |
| 27 | nouveau-y += nouveau_usif.o # userspace <-> nvif | 28 | nouveau-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__ |
| 3 | struct pwr_rail_resistor_t { | ||
| 4 | u8 mohm; | ||
| 5 | bool enabled; | ||
| 6 | }; | ||
| 7 | |||
| 3 | struct pwr_rail_t { | 8 | struct 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 | ||
| 10 | struct nvbios_iccsense { | 16 | struct 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__ |
| 3 | struct nvbios_vmap { | 3 | struct nvbios_vmap { |
| 4 | u8 max0; | ||
| 5 | u8 max1; | ||
| 6 | u8 max2; | ||
| 4 | }; | 7 | }; |
| 5 | 8 | ||
| 6 | u16 nvbios_vmap_table(struct nvkm_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len); | 9 | u16 nvbios_vmap_table(struct nvkm_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len); |
| @@ -8,7 +11,7 @@ u16 nvbios_vmap_parse(struct nvkm_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, | |||
| 8 | struct nvbios_vmap *); | 11 | struct nvbios_vmap *); |
| 9 | 12 | ||
| 10 | struct nvbios_vmap_entry { | 13 | struct 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__ | ||
| 3 | struct 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 | }; | ||
| 17 | struct nvbios_vpstate_entry { | ||
| 18 | u8 pstate; | ||
| 19 | u16 clock_mhz; | ||
| 20 | }; | ||
| 21 | int nvbios_vpstate_parse(struct nvkm_bios *, struct nvbios_vpstate_header *); | ||
| 22 | int 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 @@ | |||
| 6 | struct nvbios_pll; | 6 | struct nvbios_pll; |
| 7 | struct nvkm_pll_vals; | 7 | struct 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 | |||
| 9 | enum nv_clk_src { | 13 | enum 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 | ||
| 57 | struct nvkm_pstate { | 62 | struct nvkm_pstate { |
| @@ -67,7 +72,8 @@ struct nvkm_pstate { | |||
| 67 | struct nvkm_domain { | 72 | struct 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); | |||
| 110 | int nvkm_clk_ustate(struct nvkm_clk *, int req, int pwr); | 122 | int nvkm_clk_ustate(struct nvkm_clk *, int req, int pwr); |
| 111 | int nvkm_clk_astate(struct nvkm_clk *, int req, int rel, bool wait); | 123 | int nvkm_clk_astate(struct nvkm_clk *, int req, int rel, bool wait); |
| 112 | int nvkm_clk_dstate(struct nvkm_clk *, int req, int rel); | 124 | int nvkm_clk_dstate(struct nvkm_clk *, int req, int rel); |
| 113 | int nvkm_clk_tstate(struct nvkm_clk *, int req, int rel); | 125 | int nvkm_clk_tstate(struct nvkm_clk *, u8 temperature); |
| 114 | 126 | ||
| 115 | int nv04_clk_new(struct nvkm_device *, int, struct nvkm_clk **); | 127 | int nv04_clk_new(struct nvkm_device *, int, struct nvkm_clk **); |
| 116 | int nv40_clk_new(struct nvkm_device *, int, struct nvkm_clk **); | 128 | int 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 | ||
| 32 | int nvkm_volt_map(struct nvkm_volt *volt, u8 id, u8 temperature); | ||
| 33 | int nvkm_volt_map_min(struct nvkm_volt *volt, u8 id); | ||
| 20 | int nvkm_volt_get(struct nvkm_volt *); | 34 | int nvkm_volt_get(struct nvkm_volt *); |
| 21 | int nvkm_volt_set_id(struct nvkm_volt *, u8 id, int condition); | 35 | int nvkm_volt_set_id(struct nvkm_volt *, u8 id, u8 min_id, u8 temp, |
| 36 | int condition); | ||
| 22 | 37 | ||
| 23 | int nv40_volt_new(struct nvkm_device *, int, struct nvkm_volt **); | 38 | int nv40_volt_new(struct nvkm_device *, int, struct nvkm_volt **); |
| 39 | int gf100_volt_new(struct nvkm_device *, int, struct nvkm_volt **); | ||
| 24 | int gk104_volt_new(struct nvkm_device *, int, struct nvkm_volt **); | 40 | int gk104_volt_new(struct nvkm_device *, int, struct nvkm_volt **); |
| 25 | int gk20a_volt_new(struct nvkm_device *, int, struct nvkm_volt **); | 41 | int gk20a_volt_new(struct nvkm_device *, int, struct nvkm_volt **); |
| 26 | int gm20b_volt_new(struct nvkm_device *, int, struct nvkm_volt **); | 42 | int 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 | |||
| 36 | static enum led_brightness | ||
| 37 | nouveau_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 | |||
| 53 | static void | ||
| 54 | nouveau_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 | |||
| 77 | int | ||
| 78 | nouveau_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 | |||
| 111 | void | ||
| 112 | nouveau_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 | |||
| 120 | void | ||
| 121 | nouveau_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 | |||
| 129 | void | ||
| 130 | nouveau_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 | |||
| 30 | struct led_classdev; | ||
| 31 | |||
| 32 | struct nouveau_led { | ||
| 33 | struct drm_device *dev; | ||
| 34 | |||
| 35 | struct led_classdev led; | ||
| 36 | }; | ||
| 37 | |||
| 38 | static inline struct nouveau_led * | ||
| 39 | nouveau_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) | ||
| 46 | int nouveau_led_init(struct drm_device *dev); | ||
| 47 | void nouveau_led_suspend(struct drm_device *dev); | ||
| 48 | void nouveau_led_resume(struct drm_device *dev); | ||
| 49 | void nouveau_led_fini(struct drm_device *dev); | ||
| 50 | #else | ||
| 51 | static inline int nouveau_led_init(struct drm_device *dev) { return 0; }; | ||
| 52 | static inline void nouveau_led_suspend(struct drm_device *dev) { }; | ||
| 53 | static inline void nouveau_led_resume(struct drm_device *dev) { }; | ||
| 54 | static 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 | |||
| 45 | g94_sor_output_func = { | 45 | g94_sor_output_func = { |
| 46 | }; | 46 | }; |
| 47 | 47 | ||
| 48 | int | ||
| 49 | g94_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 | |||
| 31 | nvkm-y += nvkm/subdev/bios/therm.o | 31 | nvkm-y += nvkm/subdev/bios/therm.o |
| 32 | nvkm-y += nvkm/subdev/bios/vmap.o | 32 | nvkm-y += nvkm/subdev/bios/vmap.o |
| 33 | nvkm-y += nvkm/subdev/bios/volt.o | 33 | nvkm-y += nvkm/subdev/bios/volt.o |
| 34 | nvkm-y += nvkm/subdev/bios/vpstate.o | ||
| 34 | nvkm-y += nvkm/subdev/bios/xpio.o | 35 | nvkm-y += nvkm/subdev/bios/xpio.o |
| 35 | nvkm-y += nvkm/subdev/bios/M0203.o | 36 | nvkm-y += nvkm/subdev/bios/M0203.o |
| 36 | nvkm-y += nvkm/subdev/bios/M0205.o | 37 | nvkm-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 | ||
| 28 | static u16 | 29 | static 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 | |||
| 28 | static u32 | ||
| 29 | nvbios_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 | |||
| 41 | int | ||
| 42 | nvbios_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 | |||
| 69 | int | ||
| 70 | nvbios_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 | *****************************************************************************/ |
| 78 | static bool | ||
| 79 | nvkm_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 | |||
| 110 | static struct nvkm_cstate * | ||
| 111 | nvkm_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 | |||
| 145 | static struct nvkm_cstate * | ||
| 146 | nvkm_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 | |||
| 77 | static int | 160 | static int |
| 78 | nvkm_cstate_prog(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei) | 161 | nvkm_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 | |||
| 138 | nvkm_cstate_new(struct nvkm_clk *clk, int idx, struct nvkm_pstate *pstate) | 224 | nvkm_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 | |||
| 175 | nvkm_pstate_prog(struct nvkm_clk *clk, int pstatei) | 266 | nvkm_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 | ||
| 206 | static void | 298 | static 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 | ||
| 450 | int | 542 | int |
| 451 | nvkm_clk_tstate(struct nvkm_clk *clk, int req, int rel) | 543 | nvkm_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 | ||
| 460 | int | 551 | int |
| @@ -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 | |||
| 561 | nvkm_clk_ctor(const struct nvkm_clk_func *func, struct nvkm_device *device, | 652 | nvkm_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 | ||
| 52 | int | 52 | int |
| 53 | gf100_fb_oneinit(struct nvkm_fb *fb) | 53 | gf100_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 | ||
| 213 | static int | ||
| 214 | nv50_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 | |||
| 213 | static void | 230 | static void |
| 214 | nv50_fb_init(struct nvkm_fb *base) | 231 | nv50_fb_init(struct nvkm_fb *base) |
| 215 | { | 232 | { |
| @@ -245,6 +262,7 @@ nv50_fb_dtor(struct nvkm_fb *base) | |||
| 245 | static const struct nvkm_fb_func | 262 | static const struct nvkm_fb_func |
| 246 | nv50_fb_ = { | 263 | nv50_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 *, | |||
| 24 | int gf100_ram_get(struct nvkm_ram *, u64, u32, u32, u32, struct nvkm_mem **); | 24 | int gf100_ram_get(struct nvkm_ram *, u64, u32, u32, u32, struct nvkm_mem **); |
| 25 | void gf100_ram_put(struct nvkm_ram *, struct nvkm_mem **); | 25 | void gf100_ram_put(struct nvkm_ram *, struct nvkm_mem **); |
| 26 | 26 | ||
| 27 | int gk104_ram_ctor(struct nvkm_fb *, struct nvkm_ram **, u32); | ||
| 27 | int gk104_ram_init(struct nvkm_ram *ram); | 28 | int 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 = { | |||
| 1530 | int | 1538 | int |
| 1531 | gk104_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram) | 1539 | gk104_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram) |
| 1532 | { | 1540 | { |
| 1541 | return gk104_ram_ctor(fb, pram, 0x022554); | ||
| 1542 | } | ||
| 1543 | |||
| 1544 | int | ||
| 1545 | gk104_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 | ||
| 26 | static const struct nvkm_ram_func | ||
| 27 | gm107_ram_func = { | ||
| 28 | .init = gk104_ram_init, | ||
| 29 | .get = gf100_ram_get, | ||
| 30 | .put = gf100_ram_put, | ||
| 31 | }; | ||
| 32 | |||
| 33 | int | 26 | int |
| 34 | gm107_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram) | 27 | gm107_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 | ||
| 98 | static void | 98 | static void |
| 99 | nvkm_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 | |||
| 115 | static void | ||
| 116 | nvkm_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 | |||
| 138 | static void | ||
| 139 | nvkm_iccsense_sensor_config(struct nvkm_iccsense *iccsense, | 99 | nvkm_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 | ||
| 155 | int | 107 | int |
| @@ -196,7 +148,6 @@ nvkm_iccsense_dtor(struct nvkm_subdev *subdev) | |||
| 196 | static struct nvkm_iccsense_sensor* | 148 | static struct nvkm_iccsense_sensor* |
| 197 | nvkm_iccsense_create_sensor(struct nvkm_iccsense *iccsense, u8 id) | 149 | nvkm_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 | ||
| 16 | struct nvkm_iccsense_rail { | 16 | struct 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 | ||
| 29 | static u8 * | 29 | static u8 * |
| 30 | mxms_data(struct nvkm_mxm *mxm) | 30 | mxms_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 @@ | |||
| 1 | nvkm-y += nvkm/subdev/volt/base.o | 1 | nvkm-y += nvkm/subdev/volt/base.o |
| 2 | nvkm-y += nvkm/subdev/volt/gpio.o | 2 | nvkm-y += nvkm/subdev/volt/gpio.o |
| 3 | nvkm-y += nvkm/subdev/volt/nv40.o | 3 | nvkm-y += nvkm/subdev/volt/nv40.o |
| 4 | nvkm-y += nvkm/subdev/volt/gf100.o | ||
| 4 | nvkm-y += nvkm/subdev/volt/gk104.o | 5 | nvkm-y += nvkm/subdev/volt/gk104.o |
| 5 | nvkm-y += nvkm/subdev/volt/gk20a.o | 6 | nvkm-y += nvkm/subdev/volt/gk20a.o |
| 6 | nvkm-y += nvkm/subdev/volt/gm20b.o | 7 | nvkm-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 | ||
| 30 | int | 31 | int |
| 31 | nvkm_volt_get(struct nvkm_volt *volt) | 32 | nvkm_volt_get(struct nvkm_volt *volt) |
| @@ -50,23 +51,35 @@ static int | |||
| 50 | nvkm_volt_set(struct nvkm_volt *volt, u32 uv) | 51 | nvkm_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 | ||
| 68 | static int | 81 | int |
| 69 | nvkm_volt_map(struct nvkm_volt *volt, u8 id) | 82 | nvkm_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 | ||
| 90 | int | 103 | int |
| 91 | nvkm_volt_set_id(struct nvkm_volt *volt, u8 id, int condition) | 104 | nvkm_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 | |||
| 159 | int | ||
| 160 | nvkm_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) | |||
| 112 | static void | 185 | static void |
| 113 | nvkm_volt_parse_bios(struct nvkm_bios *bios, struct nvkm_volt *volt) | 186 | nvkm_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 | ||
| 156 | static int | 232 | static int |
| 233 | nvkm_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 | |||
| 240 | static int | ||
| 157 | nvkm_volt_init(struct nvkm_subdev *subdev) | 241 | nvkm_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 | ||
| 254 | static int | ||
| 255 | nvkm_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 | |||
| 170 | static void * | 269 | static void * |
| 171 | nvkm_volt_dtor(struct nvkm_subdev *subdev) | 270 | nvkm_volt_dtor(struct nvkm_subdev *subdev) |
| 172 | { | 271 | { |
| @@ -177,6 +276,7 @@ static const struct nvkm_subdev_func | |||
| 177 | nvkm_volt = { | 276 | nvkm_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 | ||
| 182 | void | 282 | void |
| @@ -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 | |||
| 28 | static int | ||
| 29 | gf100_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 | |||
| 40 | int | ||
| 41 | gf100_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 | |||
| 50 | static const struct nvkm_volt_func | ||
| 51 | gf100_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 | |||
| 58 | int | ||
| 59 | gf100_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) |
| 32 | struct gk104_volt { | 33 | struct 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 | ||
| 68 | static int | ||
| 69 | gk104_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 | |||
| 67 | static const struct nvkm_volt_func | 84 | static const struct nvkm_volt_func |
| 68 | gk104_volt_pwm = { | 85 | gk104_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 | ||
| 76 | int | 97 | int |
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 | ||
| 11 | struct nvkm_volt_func { | 11 | struct 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 | ||
| 19 | int nvkm_voltgpio_init(struct nvkm_volt *); | 21 | int nvkm_voltgpio_init(struct nvkm_volt *); |
| @@ -23,4 +25,6 @@ int nvkm_voltgpio_set(struct nvkm_volt *, u8); | |||
| 23 | int nvkm_voltpwm_init(struct nvkm_volt *volt); | 25 | int nvkm_voltpwm_init(struct nvkm_volt *volt); |
| 24 | int nvkm_voltpwm_get(struct nvkm_volt *volt); | 26 | int nvkm_voltpwm_get(struct nvkm_volt *volt); |
| 25 | int nvkm_voltpwm_set(struct nvkm_volt *volt, u32 uv); | 27 | int nvkm_voltpwm_set(struct nvkm_volt *volt, u32 uv); |
| 28 | |||
| 29 | int gf100_volt_oneinit(struct nvkm_volt *); | ||
| 26 | #endif | 30 | #endif |
