aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLyude Paul <lyude@redhat.com>2018-02-01 13:13:55 -0500
committerBen Skeggs <bskeggs@redhat.com>2018-02-02 00:24:08 -0500
commitb138eca661ccee2b43f8ef3cfd952a5c71c1dc90 (patch)
tree3f423a690a37041f9e062c8c35804a3d4fc05ae7
parentf4778f08a038d48ab8528416a51bf7ad231f9cc1 (diff)
drm/nouveau: Add support for basic clockgating on Kepler1
This adds support for enabling automatic clockgating on nvidia GPUs for Kepler1. While this is not technically a clockgating level, it does enable clockgating using the clockgating values initially set by the vbios (which should be safe to use). This introduces two therm helpers for controlling basic clockgating: nvkm_therm_clkgate_enable() - enables clockgating through CG_CTRL, done after initializing the GPU fully nvkm_therm_clkgate_fini() - prepares clockgating for suspend or driver unload A lot of this code was originally going to be based off of fermi; however it turns out that while Fermi's the first line of GPUs that introduced this kind of power saving, Fermi requires more fine tuned control of the CG_CTRL registers from the driver while reclocking that we don't entirely understand yet. For the simple parts we will be sharing with Fermi for certain however, we at least add those into a new subdev/therm/gf100.h header. Signed-off-by: Lyude Paul <lyude@redhat.com> Reviewed-by: Martin Peres <martin.peres@free.fr> Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/therm.h5
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/device/base.c17
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/therm/Kbuild1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c58
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf100.h35
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf119.c8
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/therm/gk104.c135
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/therm/gk104.h48
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/therm/priv.h15
9 files changed, 301 insertions, 21 deletions
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/therm.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/therm.h
index b1ac47eb786e..240b19bb4667 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/therm.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/therm.h
@@ -85,17 +85,22 @@ struct nvkm_therm {
85 85
86 int (*attr_get)(struct nvkm_therm *, enum nvkm_therm_attr_type); 86 int (*attr_get)(struct nvkm_therm *, enum nvkm_therm_attr_type);
87 int (*attr_set)(struct nvkm_therm *, enum nvkm_therm_attr_type, int); 87 int (*attr_set)(struct nvkm_therm *, enum nvkm_therm_attr_type, int);
88
89 bool clkgating_enabled;
88}; 90};
89 91
90int nvkm_therm_temp_get(struct nvkm_therm *); 92int nvkm_therm_temp_get(struct nvkm_therm *);
91int nvkm_therm_fan_sense(struct nvkm_therm *); 93int nvkm_therm_fan_sense(struct nvkm_therm *);
92int nvkm_therm_cstate(struct nvkm_therm *, int, int); 94int nvkm_therm_cstate(struct nvkm_therm *, int, int);
95void nvkm_therm_clkgate_enable(struct nvkm_therm *);
96void nvkm_therm_clkgate_fini(struct nvkm_therm *, bool);
93 97
94int nv40_therm_new(struct nvkm_device *, int, struct nvkm_therm **); 98int nv40_therm_new(struct nvkm_device *, int, struct nvkm_therm **);
95int nv50_therm_new(struct nvkm_device *, int, struct nvkm_therm **); 99int nv50_therm_new(struct nvkm_device *, int, struct nvkm_therm **);
96int g84_therm_new(struct nvkm_device *, int, struct nvkm_therm **); 100int g84_therm_new(struct nvkm_device *, int, struct nvkm_therm **);
97int gt215_therm_new(struct nvkm_device *, int, struct nvkm_therm **); 101int gt215_therm_new(struct nvkm_device *, int, struct nvkm_therm **);
98int gf119_therm_new(struct nvkm_device *, int, struct nvkm_therm **); 102int gf119_therm_new(struct nvkm_device *, int, struct nvkm_therm **);
103int gk104_therm_new(struct nvkm_device *, int, struct nvkm_therm **);
99int gm107_therm_new(struct nvkm_device *, int, struct nvkm_therm **); 104int gm107_therm_new(struct nvkm_device *, int, struct nvkm_therm **);
100int gm200_therm_new(struct nvkm_device *, int, struct nvkm_therm **); 105int gm200_therm_new(struct nvkm_device *, int, struct nvkm_therm **);
101int gp100_therm_new(struct nvkm_device *, int, struct nvkm_therm **); 106int gp100_therm_new(struct nvkm_device *, int, struct nvkm_therm **);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
index a4a5ffce03d0..eab529dceb73 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
@@ -28,6 +28,7 @@
28#include <core/option.h> 28#include <core/option.h>
29 29
30#include <subdev/bios.h> 30#include <subdev/bios.h>
31#include <subdev/therm.h>
31 32
32static DEFINE_MUTEX(nv_devices_mutex); 33static DEFINE_MUTEX(nv_devices_mutex);
33static LIST_HEAD(nv_devices); 34static LIST_HEAD(nv_devices);
@@ -1682,7 +1683,7 @@ nve4_chipset = {
1682 .mxm = nv50_mxm_new, 1683 .mxm = nv50_mxm_new,
1683 .pci = gk104_pci_new, 1684 .pci = gk104_pci_new,
1684 .pmu = gk104_pmu_new, 1685 .pmu = gk104_pmu_new,
1685 .therm = gf119_therm_new, 1686 .therm = gk104_therm_new,
1686 .timer = nv41_timer_new, 1687 .timer = nv41_timer_new,
1687 .top = gk104_top_new, 1688 .top = gk104_top_new,
1688 .volt = gk104_volt_new, 1689 .volt = gk104_volt_new,
@@ -1721,7 +1722,7 @@ nve6_chipset = {
1721 .mxm = nv50_mxm_new, 1722 .mxm = nv50_mxm_new,
1722 .pci = gk104_pci_new, 1723 .pci = gk104_pci_new,
1723 .pmu = gk104_pmu_new, 1724 .pmu = gk104_pmu_new,
1724 .therm = gf119_therm_new, 1725 .therm = gk104_therm_new,
1725 .timer = nv41_timer_new, 1726 .timer = nv41_timer_new,
1726 .top = gk104_top_new, 1727 .top = gk104_top_new,
1727 .volt = gk104_volt_new, 1728 .volt = gk104_volt_new,
@@ -1760,7 +1761,7 @@ nve7_chipset = {
1760 .mxm = nv50_mxm_new, 1761 .mxm = nv50_mxm_new,
1761 .pci = gk104_pci_new, 1762 .pci = gk104_pci_new,
1762 .pmu = gk104_pmu_new, 1763 .pmu = gk104_pmu_new,
1763 .therm = gf119_therm_new, 1764 .therm = gk104_therm_new,
1764 .timer = nv41_timer_new, 1765 .timer = nv41_timer_new,
1765 .top = gk104_top_new, 1766 .top = gk104_top_new,
1766 .volt = gk104_volt_new, 1767 .volt = gk104_volt_new,
@@ -1824,7 +1825,7 @@ nvf0_chipset = {
1824 .mxm = nv50_mxm_new, 1825 .mxm = nv50_mxm_new,
1825 .pci = gk104_pci_new, 1826 .pci = gk104_pci_new,
1826 .pmu = gk110_pmu_new, 1827 .pmu = gk110_pmu_new,
1827 .therm = gf119_therm_new, 1828 .therm = gk104_therm_new,
1828 .timer = nv41_timer_new, 1829 .timer = nv41_timer_new,
1829 .top = gk104_top_new, 1830 .top = gk104_top_new,
1830 .volt = gk104_volt_new, 1831 .volt = gk104_volt_new,
@@ -1862,7 +1863,7 @@ nvf1_chipset = {
1862 .mxm = nv50_mxm_new, 1863 .mxm = nv50_mxm_new,
1863 .pci = gk104_pci_new, 1864 .pci = gk104_pci_new,
1864 .pmu = gk110_pmu_new, 1865 .pmu = gk110_pmu_new,
1865 .therm = gf119_therm_new, 1866 .therm = gk104_therm_new,
1866 .timer = nv41_timer_new, 1867 .timer = nv41_timer_new,
1867 .top = gk104_top_new, 1868 .top = gk104_top_new,
1868 .volt = gk104_volt_new, 1869 .volt = gk104_volt_new,
@@ -1900,7 +1901,7 @@ nv106_chipset = {
1900 .mxm = nv50_mxm_new, 1901 .mxm = nv50_mxm_new,
1901 .pci = gk104_pci_new, 1902 .pci = gk104_pci_new,
1902 .pmu = gk208_pmu_new, 1903 .pmu = gk208_pmu_new,
1903 .therm = gf119_therm_new, 1904 .therm = gk104_therm_new,
1904 .timer = nv41_timer_new, 1905 .timer = nv41_timer_new,
1905 .top = gk104_top_new, 1906 .top = gk104_top_new,
1906 .volt = gk104_volt_new, 1907 .volt = gk104_volt_new,
@@ -1938,7 +1939,7 @@ nv108_chipset = {
1938 .mxm = nv50_mxm_new, 1939 .mxm = nv50_mxm_new,
1939 .pci = gk104_pci_new, 1940 .pci = gk104_pci_new,
1940 .pmu = gk208_pmu_new, 1941 .pmu = gk208_pmu_new,
1941 .therm = gf119_therm_new, 1942 .therm = gk104_therm_new,
1942 .timer = nv41_timer_new, 1943 .timer = nv41_timer_new,
1943 .top = gk104_top_new, 1944 .top = gk104_top_new,
1944 .volt = gk104_volt_new, 1945 .volt = gk104_volt_new,
@@ -2513,6 +2514,7 @@ nvkm_device_fini(struct nvkm_device *device, bool suspend)
2513 } 2514 }
2514 } 2515 }
2515 2516
2517 nvkm_therm_clkgate_fini(device->therm, suspend);
2516 2518
2517 if (device->func->fini) 2519 if (device->func->fini)
2518 device->func->fini(device, suspend); 2520 device->func->fini(device, suspend);
@@ -2602,6 +2604,7 @@ nvkm_device_init(struct nvkm_device *device)
2602 } 2604 }
2603 2605
2604 nvkm_acpi_init(device); 2606 nvkm_acpi_init(device);
2607 nvkm_therm_clkgate_enable(device->therm);
2605 2608
2606 time = ktime_to_us(ktime_get()) - time; 2609 time = ktime_to_us(ktime_get()) - time;
2607 nvdev_trace(device, "init completed in %lldus\n", time); 2610 nvdev_trace(device, "init completed in %lldus\n", time);
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/Kbuild
index 7ba56b12badd..4bac4772d8ed 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/Kbuild
@@ -10,6 +10,7 @@ nvkm-y += nvkm/subdev/therm/nv50.o
10nvkm-y += nvkm/subdev/therm/g84.o 10nvkm-y += nvkm/subdev/therm/g84.o
11nvkm-y += nvkm/subdev/therm/gt215.o 11nvkm-y += nvkm/subdev/therm/gt215.o
12nvkm-y += nvkm/subdev/therm/gf119.o 12nvkm-y += nvkm/subdev/therm/gf119.o
13nvkm-y += nvkm/subdev/therm/gk104.o
13nvkm-y += nvkm/subdev/therm/gm107.o 14nvkm-y += nvkm/subdev/therm/gm107.o
14nvkm-y += nvkm/subdev/therm/gm200.o 15nvkm-y += nvkm/subdev/therm/gm200.o
15nvkm-y += nvkm/subdev/therm/gp100.o 16nvkm-y += nvkm/subdev/therm/gp100.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c
index f27fc6d0d4c6..cf1d5af30f5f 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c
@@ -21,6 +21,7 @@
21 * 21 *
22 * Authors: Martin Peres 22 * Authors: Martin Peres
23 */ 23 */
24#include <nvkm/core/option.h>
24#include "priv.h" 25#include "priv.h"
25 26
26int 27int
@@ -297,6 +298,38 @@ nvkm_therm_attr_set(struct nvkm_therm *therm,
297 return -EINVAL; 298 return -EINVAL;
298} 299}
299 300
301void
302nvkm_therm_clkgate_enable(struct nvkm_therm *therm)
303{
304 if (!therm->func->clkgate_enable || !therm->clkgating_enabled)
305 return;
306
307 nvkm_debug(&therm->subdev,
308 "Enabling clockgating\n");
309 therm->func->clkgate_enable(therm);
310}
311
312void
313nvkm_therm_clkgate_fini(struct nvkm_therm *therm, bool suspend)
314{
315 if (!therm->func->clkgate_fini || !therm->clkgating_enabled)
316 return;
317
318 nvkm_debug(&therm->subdev,
319 "Preparing clockgating for %s\n",
320 suspend ? "suspend" : "fini");
321 therm->func->clkgate_fini(therm, suspend);
322}
323
324static void
325nvkm_therm_clkgate_oneinit(struct nvkm_therm *therm)
326{
327 if (!therm->func->clkgate_enable || !therm->clkgating_enabled)
328 return;
329
330 nvkm_info(&therm->subdev, "Clockgating enabled\n");
331}
332
300static void 333static void
301nvkm_therm_intr(struct nvkm_subdev *subdev) 334nvkm_therm_intr(struct nvkm_subdev *subdev)
302{ 335{
@@ -333,6 +366,7 @@ nvkm_therm_oneinit(struct nvkm_subdev *subdev)
333 nvkm_therm_fan_ctor(therm); 366 nvkm_therm_fan_ctor(therm);
334 nvkm_therm_fan_mode(therm, NVKM_THERM_CTRL_AUTO); 367 nvkm_therm_fan_mode(therm, NVKM_THERM_CTRL_AUTO);
335 nvkm_therm_sensor_preinit(therm); 368 nvkm_therm_sensor_preinit(therm);
369 nvkm_therm_clkgate_oneinit(therm);
336 return 0; 370 return 0;
337} 371}
338 372
@@ -374,15 +408,10 @@ nvkm_therm = {
374 .intr = nvkm_therm_intr, 408 .intr = nvkm_therm_intr,
375}; 409};
376 410
377int 411void
378nvkm_therm_new_(const struct nvkm_therm_func *func, struct nvkm_device *device, 412nvkm_therm_ctor(struct nvkm_therm *therm, struct nvkm_device *device,
379 int index, struct nvkm_therm **ptherm) 413 int index, const struct nvkm_therm_func *func)
380{ 414{
381 struct nvkm_therm *therm;
382
383 if (!(therm = *ptherm = kzalloc(sizeof(*therm), GFP_KERNEL)))
384 return -ENOMEM;
385
386 nvkm_subdev_ctor(&nvkm_therm, device, index, &therm->subdev); 415 nvkm_subdev_ctor(&nvkm_therm, device, index, &therm->subdev);
387 therm->func = func; 416 therm->func = func;
388 417
@@ -395,5 +424,18 @@ nvkm_therm_new_(const struct nvkm_therm_func *func, struct nvkm_device *device,
395 therm->attr_get = nvkm_therm_attr_get; 424 therm->attr_get = nvkm_therm_attr_get;
396 therm->attr_set = nvkm_therm_attr_set; 425 therm->attr_set = nvkm_therm_attr_set;
397 therm->mode = therm->suspend = -1; /* undefined */ 426 therm->mode = therm->suspend = -1; /* undefined */
427 therm->clkgating_enabled = false;
428}
429
430int
431nvkm_therm_new_(const struct nvkm_therm_func *func, struct nvkm_device *device,
432 int index, struct nvkm_therm **ptherm)
433{
434 struct nvkm_therm *therm;
435
436 if (!(therm = *ptherm = kzalloc(sizeof(*therm), GFP_KERNEL)))
437 return -ENOMEM;
438
439 nvkm_therm_ctor(therm, device, index, func);
398 return 0; 440 return 0;
399} 441}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf100.h b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf100.h
new file mode 100644
index 000000000000..cfb25af77c60
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf100.h
@@ -0,0 +1,35 @@
1/*
2 * Copyright 2018 Red Hat Inc.
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: Lyude Paul
23 */
24
25#ifndef __GF100_THERM_H__
26#define __GF100_THERM_H__
27
28#include <core/device.h>
29
30struct gf100_idle_filter {
31 u32 fecs;
32 u32 hubmmu;
33};
34
35#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf119.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf119.c
index 06dcfd6ee966..0981b02790e2 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf119.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf119.c
@@ -49,7 +49,7 @@ pwm_info(struct nvkm_therm *therm, int line)
49 return -ENODEV; 49 return -ENODEV;
50} 50}
51 51
52static int 52int
53gf119_fan_pwm_ctrl(struct nvkm_therm *therm, int line, bool enable) 53gf119_fan_pwm_ctrl(struct nvkm_therm *therm, int line, bool enable)
54{ 54{
55 struct nvkm_device *device = therm->subdev.device; 55 struct nvkm_device *device = therm->subdev.device;
@@ -63,7 +63,7 @@ gf119_fan_pwm_ctrl(struct nvkm_therm *therm, int line, bool enable)
63 return 0; 63 return 0;
64} 64}
65 65
66static int 66int
67gf119_fan_pwm_get(struct nvkm_therm *therm, int line, u32 *divs, u32 *duty) 67gf119_fan_pwm_get(struct nvkm_therm *therm, int line, u32 *divs, u32 *duty)
68{ 68{
69 struct nvkm_device *device = therm->subdev.device; 69 struct nvkm_device *device = therm->subdev.device;
@@ -85,7 +85,7 @@ gf119_fan_pwm_get(struct nvkm_therm *therm, int line, u32 *divs, u32 *duty)
85 return -EINVAL; 85 return -EINVAL;
86} 86}
87 87
88static int 88int
89gf119_fan_pwm_set(struct nvkm_therm *therm, int line, u32 divs, u32 duty) 89gf119_fan_pwm_set(struct nvkm_therm *therm, int line, u32 divs, u32 duty)
90{ 90{
91 struct nvkm_device *device = therm->subdev.device; 91 struct nvkm_device *device = therm->subdev.device;
@@ -102,7 +102,7 @@ gf119_fan_pwm_set(struct nvkm_therm *therm, int line, u32 divs, u32 duty)
102 return 0; 102 return 0;
103} 103}
104 104
105static int 105int
106gf119_fan_pwm_clock(struct nvkm_therm *therm, int line) 106gf119_fan_pwm_clock(struct nvkm_therm *therm, int line)
107{ 107{
108 struct nvkm_device *device = therm->subdev.device; 108 struct nvkm_device *device = therm->subdev.device;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gk104.c
new file mode 100644
index 000000000000..79806a757893
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gk104.c
@@ -0,0 +1,135 @@
1/*
2 * Copyright 2018 Red Hat Inc.
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: Lyude Paul
23 */
24#include <core/device.h>
25
26#include "priv.h"
27#include "gk104.h"
28
29void
30gk104_clkgate_enable(struct nvkm_therm *base)
31{
32 struct gk104_therm *therm = gk104_therm(base);
33 struct nvkm_device *dev = therm->base.subdev.device;
34 const struct gk104_clkgate_engine_info *order = therm->clkgate_order;
35 int i;
36
37 /* Program ENG_MANT, ENG_FILTER */
38 for (i = 0; order[i].engine != NVKM_SUBDEV_NR; i++) {
39 if (!nvkm_device_subdev(dev, order[i].engine))
40 continue;
41
42 nvkm_mask(dev, 0x20200 + order[i].offset, 0xff00, 0x4500);
43 }
44
45 /* magic */
46 nvkm_wr32(dev, 0x020288, therm->idle_filter->fecs);
47 nvkm_wr32(dev, 0x02028c, therm->idle_filter->hubmmu);
48
49 /* Enable clockgating (ENG_CLK = RUN->AUTO) */
50 for (i = 0; order[i].engine != NVKM_SUBDEV_NR; i++) {
51 if (!nvkm_device_subdev(dev, order[i].engine))
52 continue;
53
54 nvkm_mask(dev, 0x20200 + order[i].offset, 0x00ff, 0x0045);
55 }
56}
57
58void
59gk104_clkgate_fini(struct nvkm_therm *base, bool suspend)
60{
61 struct gk104_therm *therm = gk104_therm(base);
62 struct nvkm_device *dev = therm->base.subdev.device;
63 const struct gk104_clkgate_engine_info *order = therm->clkgate_order;
64 int i;
65
66 /* ENG_CLK = AUTO->RUN, ENG_PWR = RUN->AUTO */
67 for (i = 0; order[i].engine != NVKM_SUBDEV_NR; i++) {
68 if (!nvkm_device_subdev(dev, order[i].engine))
69 continue;
70
71 nvkm_mask(dev, 0x20200 + order[i].offset, 0xff, 0x54);
72 }
73}
74
75const struct gk104_clkgate_engine_info gk104_clkgate_engine_info[] = {
76 { NVKM_ENGINE_GR, 0x00 },
77 { NVKM_ENGINE_MSPDEC, 0x04 },
78 { NVKM_ENGINE_MSPPP, 0x08 },
79 { NVKM_ENGINE_MSVLD, 0x0c },
80 { NVKM_ENGINE_CE0, 0x10 },
81 { NVKM_ENGINE_CE1, 0x14 },
82 { NVKM_ENGINE_MSENC, 0x18 },
83 { NVKM_ENGINE_CE2, 0x1c },
84 { NVKM_SUBDEV_NR, 0 },
85};
86
87const struct gf100_idle_filter gk104_idle_filter = {
88 .fecs = 0x00001000,
89 .hubmmu = 0x00001000,
90};
91
92static const struct nvkm_therm_func
93gk104_therm_func = {
94 .init = gf119_therm_init,
95 .fini = g84_therm_fini,
96 .pwm_ctrl = gf119_fan_pwm_ctrl,
97 .pwm_get = gf119_fan_pwm_get,
98 .pwm_set = gf119_fan_pwm_set,
99 .pwm_clock = gf119_fan_pwm_clock,
100 .temp_get = g84_temp_get,
101 .fan_sense = gt215_therm_fan_sense,
102 .program_alarms = nvkm_therm_program_alarms_polling,
103 .clkgate_enable = gk104_clkgate_enable,
104 .clkgate_fini = gk104_clkgate_fini,
105};
106
107static int
108gk104_therm_new_(const struct nvkm_therm_func *func,
109 struct nvkm_device *device,
110 int index,
111 const struct gk104_clkgate_engine_info *clkgate_order,
112 const struct gf100_idle_filter *idle_filter,
113 struct nvkm_therm **ptherm)
114{
115 struct gk104_therm *therm = kzalloc(sizeof(*therm), GFP_KERNEL);
116
117 if (!therm)
118 return -ENOMEM;
119
120 nvkm_therm_ctor(&therm->base, device, index, func);
121 *ptherm = &therm->base;
122 therm->clkgate_order = clkgate_order;
123 therm->idle_filter = idle_filter;
124
125 return 0;
126}
127
128int
129gk104_therm_new(struct nvkm_device *device,
130 int index, struct nvkm_therm **ptherm)
131{
132 return gk104_therm_new_(&gk104_therm_func, device, index,
133 gk104_clkgate_engine_info, &gk104_idle_filter,
134 ptherm);
135}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gk104.h b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gk104.h
new file mode 100644
index 000000000000..293e7743b19b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gk104.h
@@ -0,0 +1,48 @@
1/*
2 * Copyright 2018 Red Hat Inc.
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: Lyude Paul
23 */
24
25#ifndef __GK104_THERM_H__
26#define __GK104_THERM_H__
27#define gk104_therm(p) (container_of((p), struct gk104_therm, base))
28
29#include <subdev/therm.h>
30#include "priv.h"
31#include "gf100.h"
32
33struct gk104_clkgate_engine_info {
34 enum nvkm_devidx engine;
35 u8 offset;
36};
37
38struct gk104_therm {
39 struct nvkm_therm base;
40
41 const struct gk104_clkgate_engine_info *clkgate_order;
42 const struct gf100_idle_filter *idle_filter;
43};
44
45extern const struct gk104_clkgate_engine_info gk104_clkgate_engine_info[];
46extern const struct gf100_idle_filter gk104_idle_filter;
47
48#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/priv.h
index 1f46e371d7c4..f30202dd88e7 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/priv.h
@@ -32,6 +32,8 @@
32 32
33int nvkm_therm_new_(const struct nvkm_therm_func *, struct nvkm_device *, 33int nvkm_therm_new_(const struct nvkm_therm_func *, struct nvkm_device *,
34 int index, struct nvkm_therm **); 34 int index, struct nvkm_therm **);
35void nvkm_therm_ctor(struct nvkm_therm *therm, struct nvkm_device *device,
36 int index, const struct nvkm_therm_func *func);
35 37
36struct nvkm_fan { 38struct nvkm_fan {
37 struct nvkm_therm *parent; 39 struct nvkm_therm *parent;
@@ -66,8 +68,6 @@ int nvkm_therm_fan_set(struct nvkm_therm *, bool now, int percent);
66int nvkm_therm_fan_user_get(struct nvkm_therm *); 68int nvkm_therm_fan_user_get(struct nvkm_therm *);
67int nvkm_therm_fan_user_set(struct nvkm_therm *, int percent); 69int nvkm_therm_fan_user_set(struct nvkm_therm *, int percent);
68 70
69int nvkm_therm_preinit(struct nvkm_therm *);
70
71int nvkm_therm_sensor_init(struct nvkm_therm *); 71int nvkm_therm_sensor_init(struct nvkm_therm *);
72int nvkm_therm_sensor_fini(struct nvkm_therm *, bool suspend); 72int nvkm_therm_sensor_fini(struct nvkm_therm *, bool suspend);
73void nvkm_therm_sensor_preinit(struct nvkm_therm *); 73void nvkm_therm_sensor_preinit(struct nvkm_therm *);
@@ -96,6 +96,9 @@ struct nvkm_therm_func {
96 int (*fan_sense)(struct nvkm_therm *); 96 int (*fan_sense)(struct nvkm_therm *);
97 97
98 void (*program_alarms)(struct nvkm_therm *); 98 void (*program_alarms)(struct nvkm_therm *);
99
100 void (*clkgate_enable)(struct nvkm_therm *);
101 void (*clkgate_fini)(struct nvkm_therm *, bool);
99}; 102};
100 103
101void nv40_therm_intr(struct nvkm_therm *); 104void nv40_therm_intr(struct nvkm_therm *);
@@ -112,8 +115,16 @@ void g84_therm_fini(struct nvkm_therm *);
112int gt215_therm_fan_sense(struct nvkm_therm *); 115int gt215_therm_fan_sense(struct nvkm_therm *);
113 116
114void g84_therm_init(struct nvkm_therm *); 117void g84_therm_init(struct nvkm_therm *);
118
119int gf119_fan_pwm_ctrl(struct nvkm_therm *, int, bool);
120int gf119_fan_pwm_get(struct nvkm_therm *, int, u32 *, u32 *);
121int gf119_fan_pwm_set(struct nvkm_therm *, int, u32, u32);
122int gf119_fan_pwm_clock(struct nvkm_therm *, int);
115void gf119_therm_init(struct nvkm_therm *); 123void gf119_therm_init(struct nvkm_therm *);
116 124
125void gk104_clkgate_enable(struct nvkm_therm *);
126void gk104_clkgate_fini(struct nvkm_therm *, bool);
127
117int nvkm_fanpwm_create(struct nvkm_therm *, struct dcb_gpio_func *); 128int nvkm_fanpwm_create(struct nvkm_therm *, struct dcb_gpio_func *);
118int nvkm_fantog_create(struct nvkm_therm *, struct dcb_gpio_func *); 129int nvkm_fantog_create(struct nvkm_therm *, struct dcb_gpio_func *);
119int nvkm_fannil_create(struct nvkm_therm *); 130int nvkm_fannil_create(struct nvkm_therm *);