From e09a8e8b0ae232c74b74df8346ce8af7578858c3 Mon Sep 17 00:00:00 2001
From: Lyude Paul <lyude@redhat.com>
Date: Fri, 13 Apr 2018 20:46:23 -0400
Subject: [PATCH] wip: maxwell1 power gating

currently saves ??? watts. that's a lot of watts. or not. I don't know!
---
 .../gpu/drm/nouveau/nvkm/engine/gr/gk110.c    |  33 +--
 .../gpu/drm/nouveau/nvkm/engine/gr/gk110.h    |  46 ++++
 .../gpu/drm/nouveau/nvkm/engine/gr/gm107.c    | 246 +++++++++++++++++-
 .../gpu/drm/nouveau/nvkm/subdev/fb/gk110.c    |   8 +-
 .../gpu/drm/nouveau/nvkm/subdev/fb/gm107.c    |  68 ++++-
 .../gpu/drm/nouveau/nvkm/subdev/therm/gk104.c |   2 +-
 .../gpu/drm/nouveau/nvkm/subdev/therm/gk104.h |   7 +
 .../gpu/drm/nouveau/nvkm/subdev/therm/gm107.c |  42 ++-
 8 files changed, 428 insertions(+), 24 deletions(-)
 create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110.h

diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110.c
index 7cd628c84e075..4a7318c604338 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110.c
@@ -23,6 +23,7 @@
  */
 #include "gf100.h"
 #include "gk104.h"
+#include "gk110.h"
 #include "ctxgf100.h"
 
 #include <subdev/timer.h>
@@ -158,26 +159,26 @@ gk110_gr_pack_mmio[] = {
 	{}
 };
 
-static const struct nvkm_therm_clkgate_init
+const struct nvkm_therm_clkgate_init
 gk110_clkgate_blcg_init_sked_0[] = {
 	{ 0x407000, 1, 0x00004041 },
 	{}
 };
 
-static const struct nvkm_therm_clkgate_init
+const struct nvkm_therm_clkgate_init
 gk110_clkgate_blcg_init_gpc_gcc_0[] = {
 	{ 0x419020, 1, 0x00000042 },
 	{ 0x419038, 1, 0x00000042 },
 	{}
 };
 
-static const struct nvkm_therm_clkgate_init
+const struct nvkm_therm_clkgate_init
 gk110_clkgate_blcg_init_gpc_l1c_0[] = {
 	{ 0x419cd4, 2, 0x00004042 },
 	{}
 };
 
-static const struct nvkm_therm_clkgate_init
+const struct nvkm_therm_clkgate_init
 gk110_clkgate_blcg_init_gpc_mp_0[] = {
 	{ 0x419fd0, 1, 0x00004043 },
 	{ 0x419fd8, 1, 0x00004049 },
@@ -188,32 +189,32 @@ gk110_clkgate_blcg_init_gpc_mp_0[] = {
 	{}
 };
 
-static const struct nvkm_therm_clkgate_init
+const struct nvkm_therm_clkgate_init
 gk110_clkgate_slcg_init_main_0[] = {
 	{ 0x4041f4, 1, 0x00000000 },
 	{ 0x409894, 1, 0x00000000 },
 	{}
 };
 
-static const struct nvkm_therm_clkgate_init
+const struct nvkm_therm_clkgate_init
 gk110_clkgate_slcg_init_unk_0[] = {
 	{ 0x406004, 1, 0x00000000 },
 	{}
 };
 
-static const struct nvkm_therm_clkgate_init
+const struct nvkm_therm_clkgate_init
 gk110_clkgate_slcg_init_sked_0[] = {
 	{ 0x407004, 1, 0x00000000 },
 	{}
 };
 
-static const struct nvkm_therm_clkgate_init
+const struct nvkm_therm_clkgate_init
 gk110_clkgate_slcg_init_gpc_ctxctl_0[] = {
 	{ 0x41a894, 1, 0x00000000 },
 	{}
 };
 
-static const struct nvkm_therm_clkgate_init
+const struct nvkm_therm_clkgate_init
 gk110_clkgate_slcg_init_gpc_unk_0[] = {
 	{ 0x418504, 1, 0x00000000 },
 	{ 0x41860c, 1, 0x00000000 },
@@ -221,31 +222,31 @@ gk110_clkgate_slcg_init_gpc_unk_0[] = {
 	{}
 };
 
-static const struct nvkm_therm_clkgate_init
+const struct nvkm_therm_clkgate_init
 gk110_clkgate_slcg_init_gpc_esetup_0[] = {
 	{ 0x41882c, 1, 0x00000000 },
 	{}
 };
 
-static const struct nvkm_therm_clkgate_init
+const struct nvkm_therm_clkgate_init
 gk110_clkgate_slcg_init_gpc_zcull_0[] = {
 	{ 0x418974, 1, 0x00000000 },
 	{}
 };
 
-static const struct nvkm_therm_clkgate_init
+const struct nvkm_therm_clkgate_init
 gk110_clkgate_slcg_init_gpc_l1c_0[] = {
 	{ 0x419cd8, 2, 0x00000000 },
 	{}
 };
 
-static const struct nvkm_therm_clkgate_init
+const struct nvkm_therm_clkgate_init
 gk110_clkgate_slcg_init_gpc_unk_1[] = {
 	{ 0x419c74, 1, 0x00000000 },
 	{}
 };
 
-static const struct nvkm_therm_clkgate_init
+const struct nvkm_therm_clkgate_init
 gk110_clkgate_slcg_init_gpc_mp_0[] = {
 	{ 0x419fd4, 1, 0x00004a4a },
 	{ 0x419fdc, 1, 0x00000014 },
@@ -254,13 +255,13 @@ gk110_clkgate_slcg_init_gpc_mp_0[] = {
 	{}
 };
 
-static const struct nvkm_therm_clkgate_init
+const struct nvkm_therm_clkgate_init
 gk110_clkgate_slcg_init_gpc_ppc_0[] = {
 	{ 0x41be2c, 1, 0x00000000 },
 	{}
 };
 
-static const struct nvkm_therm_clkgate_init
+const struct nvkm_therm_clkgate_init
 gk110_clkgate_slcg_init_pcounter_0[] = {
 	{ 0x1be018, 1, 0x000001ff },
 	{ 0x1bc018, 1, 0x000001ff },
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110.h
new file mode 100644
index 0000000000000..7079a22574b88
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2018 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Lyude Paul <lyude@redhat.com>
+ */
+#ifndef __GM107_GR_H__
+#define __GM107_GR_H__
+
+#include <subdev/therm.h>
+
+extern const struct nvkm_therm_clkgate_init gk110_clkgate_blcg_init_sked_0[];
+extern const struct nvkm_therm_clkgate_init gk110_clkgate_blcg_init_gpc_gcc_0[];
+extern const struct nvkm_therm_clkgate_init gk110_clkgate_blcg_init_gpc_l1c_0[];
+extern const struct nvkm_therm_clkgate_init gk110_clkgate_blcg_init_gpc_mp_0[];
+extern const struct nvkm_therm_clkgate_init gk110_clkgate_slcg_init_main_0[];
+extern const struct nvkm_therm_clkgate_init gk110_clkgate_slcg_init_unk_0[];
+extern const struct nvkm_therm_clkgate_init gk110_clkgate_slcg_init_sked_0[];
+extern const struct nvkm_therm_clkgate_init gk110_clkgate_slcg_init_gpc_ctxctl_0[];
+extern const struct nvkm_therm_clkgate_init gk110_clkgate_slcg_init_gpc_unk_0[];
+extern const struct nvkm_therm_clkgate_init gk110_clkgate_slcg_init_gpc_esetup_0[];
+extern const struct nvkm_therm_clkgate_init gk110_clkgate_slcg_init_gpc_zcull_0[];
+extern const struct nvkm_therm_clkgate_init gk110_clkgate_slcg_init_gpc_l1c_0[];
+extern const struct nvkm_therm_clkgate_init gk110_clkgate_slcg_init_gpc_unk_1[];
+extern const struct nvkm_therm_clkgate_init gk110_clkgate_slcg_init_gpc_mp_0[];
+extern const struct nvkm_therm_clkgate_init gk110_clkgate_slcg_init_gpc_ppc_0[];
+extern const struct nvkm_therm_clkgate_init gk110_clkgate_slcg_init_pcounter_0[];
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c
index 92e31d3972075..edfec84bd8299 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c
@@ -23,12 +23,15 @@
  */
 #include "gf100.h"
 #include "ctxgf100.h"
+#include "gk104.h"
+#include "gk110.h"
 
 #include <subdev/bios.h>
 #include <subdev/bios/bit.h>
 #include <subdev/bios/init.h>
 #include <subdev/bios/P0260.h>
 #include <subdev/fb.h>
+#include <subdev/therm.h>
 
 #include <nvif/class.h>
 
@@ -280,6 +283,247 @@ gm107_gr_pack_mmio[] = {
 	{}
 };
 
+static const struct nvkm_therm_clkgate_init
+gm107_clkgate_blcg_init_unk_0[] = {
+	{ 0x406000, 1, 0x00004044 },
+	{ 0x405860, 1, 0x00004042 },
+	{ 0x40590c, 1, 0x00004044 },
+};
+
+static const struct nvkm_therm_clkgate_init
+gm107_clkgate_blcg_init_gpc_unk_0[] = {
+	{ 0x418500, 1, 0x00004044 },
+	{ 0x418608, 1, 0x00004042 },
+	{ 0x418688, 1, 0x00004042 },
+	{ 0x418718, 1, 0x00000042 },
+	{}
+};
+
+static const struct nvkm_therm_clkgate_init
+gm107_clkgate_blcg_init_gpc_unk_1[] = {
+	{ 0x418cf0, 1, 0x00004044 },
+	{ 0x418d70, 1, 0x00004044 },
+	{ 0x418f0c, 1, 0x00004044 },
+	{ 0x418e0c, 1, 0x00004044 },
+	{}
+};
+
+static const struct nvkm_therm_clkgate_init
+gm107_clkgate_blcg_init_gpc_tex_0[] = {
+	{ 0x419a40, 9, 0x00004042 },
+	{}
+};
+
+static const struct nvkm_therm_clkgate_init
+gm107_clkgate_blcg_init_gpc_l1c_0[] = {
+	{ 0x419cd4, 2, 0x00000002 },
+	{}
+};
+
+static const struct nvkm_therm_clkgate_init
+gm107_clkgate_blcg_init_gpc_mp_0[] = {
+	{ 0x419fd0, 1, 0x00000044 },
+	{ 0x419fd8, 1, 0x00000045 },
+	{ 0x419fe0, 1, 0x00000044 },
+	{ 0x419fe8, 1, 0x00000042 },
+	{ 0x419ff0, 1, 0x00000045 },
+	{ 0x419ff8, 1, 0x00000002 },
+	{}
+};
+
+static const struct nvkm_therm_clkgate_init
+gm107_clkgate_blcg_init_gpc_ppc_0[] = {
+	{ 0x41be28, 1, 0x00000042 },
+	{ 0x41bfe8, 1, 0x00004044 },
+	{ 0x41bed0, 1, 0x00004044 },
+	{}
+};
+
+static const struct nvkm_therm_clkgate_init
+gm107_clkgate_slcg_init_main_0[] = {
+	{ 0x4041f4, 1, 0x00000002 },
+	{ 0x409894, 1, 0x00000000 },
+	{}
+};
+
+static const struct nvkm_therm_clkgate_init
+gm107_clkgate_slcg_init_rstr2d_0[] = {
+	{ 0x4078c4, 1, 0x00000000 },
+	{}
+};
+
+static const struct nvkm_therm_clkgate_init
+gm107_clkgate_slcg_init_unk_0[] = {
+	{ 0x406004, 1, 0x00000000 },
+	{ 0x405864, 1, 0x00000000 },
+	{ 0x405910, 1, 0xfffffff0 },
+	{}
+};
+
+static const struct nvkm_therm_clkgate_init
+gm107_clkgate_slcg_init_gcc_0[] = {
+	{ 0x408044, 1, 0x00000000 },
+	{}
+};
+
+static const struct nvkm_therm_clkgate_init
+gm107_clkgate_slcg_init_gpc_unk_0[] = {
+	{ 0x418504, 1, 0x0001fffe },
+	{ 0x41860c, 1, 0x00000000 },
+	{ 0x41868c, 1, 0x00000000 },
+	{ 0x41871c, 1, 0x00000000 },
+	{ 0x418388, 1, 0x00000000 },
+	{}
+};
+
+static const struct nvkm_therm_clkgate_init
+gm107_clkgate_slcg_init_gpc_tpbus_0[] = {
+	{ 0x418bc0, 1, 0x00000004 },
+	{}
+};
+
+static const struct nvkm_therm_clkgate_init
+gm107_clkgate_slcg_init_gpc_zcull_0[] = {
+	{ 0x418974, 1, 0x00000028 },
+	{}
+};
+
+static const struct nvkm_therm_clkgate_init
+gm107_clkgate_slcg_init_gpc_tpconf_1[] = {
+	{ 0x418c74, 1, 0xffffffc0 },
+	{}
+};
+
+static const struct nvkm_therm_clkgate_init
+gm107_clkgate_slcg_init_gpc_unk_1[] = {
+	{ 0x418504, 1, 0x0001fffe },
+	{ 0x41860c, 1, 0x00000000 },
+	{ 0x41868c, 1, 0x00000000 },
+	{ 0x41871c, 1, 0x00000000 },
+	{ 0x418388, 1, 0x00000000 },
+	{}
+};
+
+static const struct nvkm_therm_clkgate_init
+gm107_clkgate_slcg_init_gpc_gcc_0[] = {
+	{ 0x419024, 1, 0x000001fe },
+	{}
+};
+
+static const struct nvkm_therm_clkgate_init
+gm107_clkgate_slcg_init_gpc_ffb_0[] = {
+	{ 0x41889c, 1, 0x00000000 },
+	{}
+};
+
+static const struct nvkm_therm_clkgate_init
+gm107_clkgate_slcg_init_gpc_tex_0[] = {
+	{ 0x419d64, 1, 0x00000000 },
+	{ 0x419a44, 9, 0x00000000 },
+	{}
+};
+
+static const struct nvkm_therm_clkgate_init
+gm107_clkgate_slcg_init_gpc_poly_0[] = {
+	{ 0x41986c, 1, 0x00001fc4 },
+	{}
+};
+
+static const struct nvkm_therm_clkgate_init
+gm107_clkgate_slcg_init_gpc_unk_2[] = {
+	{ 0x419c74, 1, 0x0000001e },
+	{}
+};
+
+static const struct nvkm_therm_clkgate_init
+gm107_clkgate_slcg_init_gpc_mp_0[] = {
+	{ 0x419fd4, 3, 0x00000000 },
+	{ 0x419ff4, 2, 0x00000000 },
+	{}
+};
+
+static const struct nvkm_therm_clkgate_init
+gm107_clkgate_slcg_init_ppc_0[] = {
+	{ 0x41be2c, 1, 0x04135fc0 },
+	{ 0x41bfec, 1, 0xfffffff0 },
+	{ 0x41bed4, 1, 0xfffffffe },
+	{}
+};
+
+static const struct nvkm_therm_clkgate_init
+gm107_clkgate_slcg_init_rop_zrop_0[] = {
+	{ 0x4089ac, 1, 0x00000000 },
+	{}
+};
+
+static const struct nvkm_therm_clkgate_init
+gm107_clkgate_slcg_init_rop_0[] = {
+	{ 0x408a24, 1, 0x00000000 },
+	{}
+};
+
+static const struct nvkm_therm_clkgate_init
+gm107_clkgate_slcg_init_pcounter_0[] = {
+	{ 0x1be018, 1, 0x000001ff },
+	{ 0x1bc018, 1, 0x000001ff },
+	{ 0x1bc218, 1, 0x000001ff },
+	{ 0x1b8018, 1, 0x000001ff },
+	{ 0x1b4124, 1, 0x00000001 },
+	{}
+};
+
+static const struct nvkm_therm_clkgate_pack
+gm107_clkgate_pack[] = {
+	{ gk104_clkgate_blcg_init_main_0 },
+	{ gk104_clkgate_blcg_init_rstr2d_0 },
+	{ gm107_clkgate_blcg_init_unk_0 },
+	{ gk104_clkgate_blcg_init_gcc_0 },
+	{ gk110_clkgate_blcg_init_sked_0 },
+	{ gk104_clkgate_blcg_init_unk_1 },
+	{ gk104_clkgate_blcg_init_gpc_ctxctl_0 },
+	{ gm107_clkgate_blcg_init_gpc_unk_0 },
+	{ gk104_clkgate_blcg_init_gpc_esetup_0 },
+	{ gk104_clkgate_blcg_init_gpc_tpbus_0 },
+	{ gk104_clkgate_blcg_init_gpc_zcull_0 },
+	{ gm107_clkgate_blcg_init_gpc_unk_1 },
+	{ gk104_clkgate_blcg_init_gpc_gcc_0 },
+	{ gk104_clkgate_blcg_init_gpc_ffb_0 },
+	{ gm107_clkgate_blcg_init_gpc_tex_0 },
+	{ gk104_clkgate_blcg_init_gpc_poly_0 },
+	{ gm107_clkgate_blcg_init_gpc_l1c_0 },
+	{ gk104_clkgate_blcg_init_gpc_unk_2 },
+	{ gm107_clkgate_blcg_init_gpc_mp_0 },
+	{ gm107_clkgate_blcg_init_gpc_ppc_0 },
+	{ gk104_clkgate_blcg_init_rop_zrop_0 },
+	{ gk104_clkgate_blcg_init_rop_0 },
+	{ gk104_clkgate_blcg_init_rop_crop_0 },
+	{ gk104_clkgate_blcg_init_pxbar_0 },
+	{ gm107_clkgate_slcg_init_main_0 },
+	{ gm107_clkgate_slcg_init_rstr2d_0 },
+	{ gm107_clkgate_slcg_init_unk_0 },
+	{ gm107_clkgate_slcg_init_gcc_0 },
+	{ gk110_clkgate_slcg_init_sked_0 },
+	{ gk110_clkgate_slcg_init_gpc_ctxctl_0 },
+	{ gm107_clkgate_slcg_init_gpc_unk_0 },
+	{ gk110_clkgate_slcg_init_gpc_esetup_0 },
+	{ gm107_clkgate_slcg_init_gpc_tpbus_0 },
+	{ gm107_clkgate_slcg_init_gpc_zcull_0 },
+	{ gm107_clkgate_slcg_init_gpc_tpconf_1 },
+	{ gm107_clkgate_slcg_init_gpc_unk_1 },
+	{ gm107_clkgate_slcg_init_gpc_gcc_0 },
+	{ gm107_clkgate_slcg_init_gpc_ffb_0 },
+	{ gm107_clkgate_slcg_init_gpc_tex_0 },
+	{ gm107_clkgate_slcg_init_gpc_poly_0 },
+	{ gk110_clkgate_slcg_init_gpc_l1c_0 },
+	{ gm107_clkgate_slcg_init_gpc_unk_2 },
+	{ gm107_clkgate_slcg_init_gpc_mp_0 },
+	{ gm107_clkgate_slcg_init_ppc_0 },
+	{ gm107_clkgate_slcg_init_rop_zrop_0 },
+	{ gm107_clkgate_slcg_init_rop_0 },
+	{ gm107_clkgate_slcg_init_pcounter_0 },
+	{}
+};
+
 /*******************************************************************************
  * PGRAPH engine/subdev functions
  ******************************************************************************/
@@ -419,7 +663,7 @@ gm107_gr = {
 	.rops = gf100_gr_rops,
 	.ppc_nr = 2,
 	.grctx = &gm107_grctx,
-	.zbc = &gf100_gr_zbc,
+	.clkgate_pack = gm107_clkgate_pack,
 	.sclass = {
 		{ -1, -1, FERMI_TWOD_A },
 		{ -1, -1, KEPLER_INLINE_TO_MEMORY_B },
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk110.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk110.c
index 0d9ad9fa77746..e718cffafeb77 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk110.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk110.c
@@ -32,20 +32,20 @@
  * PGRAPH registers for clockgating
  *******************************************************************************
  */
-static const struct nvkm_therm_clkgate_init
+const struct nvkm_therm_clkgate_init
 gk110_fb_clkgate_slcg_init_bcast_0[] = {
 	{ 0x10f280, 1, 0x00000000 },
 	{}
 };
 
-static const struct nvkm_therm_clkgate_init
+const struct nvkm_therm_clkgate_init
 gk110_fb_clkgate_slcg_init_pxbar_0[] = {
 	{ 0x13cafc, 1, 0x0000007e },
 	{ 0x13cbe4, 1, 0x1ffffffe },
 	{}
 };
 
-static const struct nvkm_therm_clkgate_init
+const struct nvkm_therm_clkgate_init
 gk110_fb_clkgate_blcg_init_unk_0[] = {
 	{ 0x100d10, 1, 0x0000c242 },
 	{ 0x100d30, 1, 0x0000c242 },
@@ -55,7 +55,7 @@ gk110_fb_clkgate_blcg_init_unk_0[] = {
 	{}
 };
 
-static const struct nvkm_therm_clkgate_pack
+const struct nvkm_therm_clkgate_pack
 gk110_fb_clkgate_pack[] = {
 	{ gk110_fb_clkgate_slcg_init_bcast_0 },
 	{ gk110_fb_clkgate_slcg_init_pxbar_0 },
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm107.c
index 69c876d5d1c11..361c6a1fef869 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm107.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm107.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2012 Red Hat Inc.
+ * Copyright 2012-2018 Red Hat Inc.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -20,10 +20,75 @@
  * OTHER DEALINGS IN THE SOFTWARE.
  *
  * Authors: Ben Skeggs
+ *          Lyude Paul
  */
 #include "gf100.h"
+#include "gk104.h"
+#include "gk110.h"
 #include "ram.h"
 
+/*
+ *******************************************************************************
+ * PGRAPH registers for clockgating
+ *******************************************************************************
+ */
+static const struct nvkm_therm_clkgate_init
+gm107_fb_clkgate_slcg_init_unk_0[] = {
+	{ 0x100d14, 1, 0x00000000 },
+	{}
+};
+
+static const struct nvkm_therm_clkgate_init
+gm107_fb_clkgate_slcg_init_vm_0[] = {
+	{ 0x100c9c, 1, 0x00000000 },
+	{}
+};
+
+static const struct nvkm_therm_clkgate_init
+gm107_fb_clkgate_slcg_init_bcast_0[] = {
+	{ 0x17e050, 1, 0x00000000 },
+	{ 0x17e35c, 1, 0x00000000 },
+	{ 0x10f280, 1, 0x00000000 },
+	{}
+};
+
+static const struct nvkm_therm_clkgate_init
+gm107_fb_clkgate_slcg_init_pxbar_0[] = {
+	{ 0x13c824, 1, 0x00000000 },
+	{ 0x13cbe4, 1, 0x00000000 },
+	{}
+};
+
+static const struct nvkm_therm_clkgate_init
+gm107_fb_clkgate_blcg_init_main_0[] = {
+	{ 0x10f000, 1, 0x00000043 },
+	{ 0x17e030, 1, 0x00000044 },
+	{ 0x17e040, 1, 0x00000044 },
+	{}
+};
+
+static const struct nvkm_therm_clkgate_init
+gm107_fb_clkgate_blcg_init_unk_1[] = {
+	{ 0x17e3e0, 1, 0x00000044 },
+	{ 0x17e3c8, 1, 0x00000044 },
+	/* XXX extremely unlikely to be a BLCG/SLCG register */
+	/*{ 0x17e278, 1, 0x0007fd60 },*/
+	{}
+};
+
+static const struct nvkm_therm_clkgate_pack
+gm107_fb_clkgate_pack[] = {
+	{ gm107_fb_clkgate_slcg_init_unk_0 },
+	{ gm107_fb_clkgate_slcg_init_vm_0 },
+	{ gm107_fb_clkgate_slcg_init_bcast_0 },
+	{ gm107_fb_clkgate_slcg_init_pxbar_0 },
+	{ gk110_fb_clkgate_blcg_init_unk_0 },
+	{ gk104_fb_clkgate_blcg_init_vm_0 },
+	{ gm107_fb_clkgate_blcg_init_main_0 },
+	{ gm107_fb_clkgate_blcg_init_unk_1 },
+	{}
+};
+
 static const struct nvkm_fb_func
 gm107_fb = {
 	.dtor = gf100_fb_dtor,
@@ -33,6 +98,7 @@ gm107_fb = {
 	.intr = gf100_fb_intr,
 	.ram_new = gm107_ram_new,
 	.default_bigpage = 17,
+	.clkgate_pack = gm107_fb_clkgate_pack,
 };
 
 int
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gk104.c
index 4e03971d2e3df..efc8a23b55f86 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gk104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gk104.c
@@ -105,7 +105,7 @@ gk104_therm_func = {
 	.clkgate_fini = gk104_clkgate_fini,
 };
 
-static int
+int
 gk104_therm_new_(const struct nvkm_therm_func *func,
 		 struct nvkm_device *device,
 		 int index,
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gk104.h b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gk104.h
index 293e7743b19bb..f1de626c35694 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gk104.h
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gk104.h
@@ -45,4 +45,11 @@ struct gk104_therm {
 extern const struct gk104_clkgate_engine_info gk104_clkgate_engine_info[];
 extern const struct gf100_idle_filter gk104_idle_filter;
 
+int gk104_therm_new_(const struct nvkm_therm_func *,
+		     struct nvkm_device *,
+		     int,
+		     const struct gk104_clkgate_engine_info *,
+		     const struct gf100_idle_filter *,
+		     struct nvkm_therm **);
+
 #endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gm107.c
index 86848ece4d897..2ad3b2bf57385 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gm107.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gm107.c
@@ -22,6 +22,36 @@
  * Authors: Martin Peres
  */
 #include "priv.h"
+#include "gk104.h"
+
+void
+gm107_clkgate_enable(struct nvkm_therm *base)
+{
+	struct gk104_therm *therm = gk104_therm(base);
+	struct nvkm_device *dev = therm->base.subdev.device;
+	const struct gk104_clkgate_engine_info *order = therm->clkgate_order;
+	int i;
+
+	/* Program ENG_MANT, ENG_FILTER */
+	for (i = 0; order[i].engine != NVKM_SUBDEV_NR; i++) {
+		if (!nvkm_device_subdev(dev, order[i].engine))
+			continue;
+
+		nvkm_mask(dev, 0x20200 + order[i].offset, 0xff00, 0x2200);
+	}
+
+	/* magic */
+	nvkm_wr32(dev, 0x020288, therm->idle_filter->fecs);
+	nvkm_wr32(dev, 0x02028c, therm->idle_filter->hubmmu);
+
+	/* Enable clockgating (ENG_CLK = RUN->AUTO) */
+	for (i = 0; order[i].engine != NVKM_SUBDEV_NR; i++) {
+		if (!nvkm_device_subdev(dev, order[i].engine))
+			continue;
+
+		nvkm_mask(dev, 0x20200 + order[i].offset, 0x00ff, 0x0045);
+	}
+}
 
 static int
 gm107_fan_pwm_ctrl(struct nvkm_therm *therm, int line, bool enable)
@@ -54,6 +84,11 @@ gm107_fan_pwm_clock(struct nvkm_therm *therm, int line)
 	return therm->subdev.device->crystal * 1000;
 }
 
+const struct gf100_idle_filter gm107_idle_filter = {
+	.fecs = 0x00000000,
+	.hubmmu = 0x00000000,
+};
+
 static const struct nvkm_therm_func
 gm107_therm = {
 	.init = gf119_therm_init,
@@ -65,11 +100,16 @@ gm107_therm = {
 	.temp_get = g84_temp_get,
 	.fan_sense = gt215_therm_fan_sense,
 	.program_alarms = nvkm_therm_program_alarms_polling,
+	.clkgate_init = gf100_clkgate_init,
+	.clkgate_enable = gm107_clkgate_enable,
+	.clkgate_fini = gk104_clkgate_fini,
 };
 
 int
 gm107_therm_new(struct nvkm_device *device, int index,
 		struct nvkm_therm **ptherm)
 {
-	return nvkm_therm_new_(&gm107_therm, device, index, ptherm);
+	return gk104_therm_new_(&gm107_therm, device, index,
+				gk104_clkgate_engine_info, &gm107_idle_filter,
+				ptherm);
 }
-- 
GitLab