diff options
author | Dave Airlie <airlied@redhat.com> | 2016-10-28 00:24:56 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2016-10-28 00:24:56 -0400 |
commit | fb422950c6cd726fd36eb72a7cf84583440a18a2 (patch) | |
tree | 2ff57cfe130961f50aa855bd7d04a23f20b567f0 | |
parent | 220196b38483be6d84a295d318d48595f65da443 (diff) | |
parent | 2ecf7c43d78093a24aa44c0a14a335457f065bb2 (diff) |
Merge branch 'linux-4.9' of git://github.com/skeggsb/linux into drm-next
Karol's work which greatly improves volt/clock changes on a
heap of boards, nothing too exciting beyond a random collection of fixes.
* 'linux-4.9' of git://github.com/skeggsb/linux: (33 commits)
drm/nouveau/fb/nv50: defer DMA mapping of scratch page to oneinit() hook
drm/nouveau/fb/gf100: defer DMA mapping of scratch page to oneinit() hook
drm/nouveau/pci: set streaming DMA mask early
drm/nouveau/kms: add Maxwell to backlight initialization
drm/nouveau/bar/nv50: fix bar2 vm size
drm/nouveau/disp: remove unused function in sorg94.c
drm/nouveau/volt: use kernel's 64-bit signed division function
drm/nouveau/core: add missing header dependencies
drm/nouveau/gr/nv3x: add 0x0597 kelvin 3d class support
drm/nouveau/drm/nouveau: add a LED driver for the NVIDIA logo
drm/nouveau/fb/ram: Use Kepler implementation on Maxwell
drm/nouveau/volt: Make use of cvb coefficients
drm/nouveau/volt/gf100-: Add speedo
drm/nouveau/volt: Add implementation for gf100
drm/nouveau/bios/vmap: unk0 field is the mode
drm/nouveau/volt: Don't require perfect fit
drm/nouveau/clk: Allow boosting only when NvBoost is set
drm/nouveau/bios: Add parsing of VPSTATE table
drm/nouveau/clk: Respect voltage limits in nvkm_cstate_prog
drm/nouveau/clk: Fixup cstate selection
...
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 |