1*677dec6eSriastradh /*	$NetBSD: nouveau_nvkm_engine_pm_gf100.c,v 1.3 2021/12/18 23:45:37 riastradh Exp $	*/
2d350ecf5Sriastradh 
3d350ecf5Sriastradh /*
4d350ecf5Sriastradh  * Copyright 2013 Red Hat Inc.
5d350ecf5Sriastradh  *
6d350ecf5Sriastradh  * Permission is hereby granted, free of charge, to any person obtaining a
7d350ecf5Sriastradh  * copy of this software and associated documentation files (the "Software"),
8d350ecf5Sriastradh  * to deal in the Software without restriction, including without limitation
9d350ecf5Sriastradh  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10d350ecf5Sriastradh  * and/or sell copies of the Software, and to permit persons to whom the
11d350ecf5Sriastradh  * Software is furnished to do so, subject to the following conditions:
12d350ecf5Sriastradh  *
13d350ecf5Sriastradh  * The above copyright notice and this permission notice shall be included in
14d350ecf5Sriastradh  * all copies or substantial portions of the Software.
15d350ecf5Sriastradh  *
16d350ecf5Sriastradh  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17d350ecf5Sriastradh  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18d350ecf5Sriastradh  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19d350ecf5Sriastradh  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
20d350ecf5Sriastradh  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21d350ecf5Sriastradh  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22d350ecf5Sriastradh  * OTHER DEALINGS IN THE SOFTWARE.
23d350ecf5Sriastradh  *
24d350ecf5Sriastradh  * Authors: Ben Skeggs
25d350ecf5Sriastradh  */
26d350ecf5Sriastradh #include <sys/cdefs.h>
27*677dec6eSriastradh __KERNEL_RCSID(0, "$NetBSD: nouveau_nvkm_engine_pm_gf100.c,v 1.3 2021/12/18 23:45:37 riastradh Exp $");
28d350ecf5Sriastradh 
29d350ecf5Sriastradh #include "gf100.h"
30d350ecf5Sriastradh 
31d350ecf5Sriastradh const struct nvkm_specsrc
32d350ecf5Sriastradh gf100_pbfb_sources[] = {
33d350ecf5Sriastradh 	{ 0x10f100, (const struct nvkm_specmux[]) {
34d350ecf5Sriastradh 			{ 0x1, 0, "unk0" },
35d350ecf5Sriastradh 			{ 0x3f, 4, "unk4" },
36d350ecf5Sriastradh 			{}
37d350ecf5Sriastradh 		}, "pbfb_broadcast_pm_unk100" },
38d350ecf5Sriastradh 	{}
39d350ecf5Sriastradh };
40d350ecf5Sriastradh 
41d350ecf5Sriastradh const struct nvkm_specsrc
42d350ecf5Sriastradh gf100_pmfb_sources[] = {
43d350ecf5Sriastradh 	{ 0x140028, (const struct nvkm_specmux[]) {
44d350ecf5Sriastradh 			{ 0x3fff, 0, "unk0" },
45d350ecf5Sriastradh 			{ 0x7, 16, "unk16" },
46d350ecf5Sriastradh 			{ 0x3, 24, "unk24" },
47d350ecf5Sriastradh 			{ 0x2, 29, "unk29" },
48d350ecf5Sriastradh 			{}
49d350ecf5Sriastradh 		}, "pmfb0_pm_unk28" },
50d350ecf5Sriastradh 	{}
51d350ecf5Sriastradh };
52d350ecf5Sriastradh 
53d350ecf5Sriastradh static const struct nvkm_specsrc
54d350ecf5Sriastradh gf100_l1_sources[] = {
55d350ecf5Sriastradh 	{ 0x5044a8, (const struct nvkm_specmux[]) {
56d350ecf5Sriastradh 			{ 0x3f, 0, "sel", true },
57d350ecf5Sriastradh 			{}
58d350ecf5Sriastradh 		}, "pgraph_gpc0_tpc0_l1_pm_mux" },
59d350ecf5Sriastradh 	{}
60d350ecf5Sriastradh };
61d350ecf5Sriastradh 
62d350ecf5Sriastradh static const struct nvkm_specsrc
63d350ecf5Sriastradh gf100_tex_sources[] = {
64d350ecf5Sriastradh 	{ 0x5042c0, (const struct nvkm_specmux[]) {
65d350ecf5Sriastradh 			{ 0xf, 0, "sel0", true },
66d350ecf5Sriastradh 			{ 0x7, 8, "sel1", true },
67d350ecf5Sriastradh 			{}
68d350ecf5Sriastradh 		}, "pgraph_gpc0_tpc0_tex_pm_mux_c_d" },
69d350ecf5Sriastradh 	{}
70d350ecf5Sriastradh };
71d350ecf5Sriastradh 
72d350ecf5Sriastradh static const struct nvkm_specsrc
73d350ecf5Sriastradh gf100_unk400_sources[] = {
74d350ecf5Sriastradh 	{ 0x50440c, (const struct nvkm_specmux[]) {
75d350ecf5Sriastradh 			{ 0x3f, 0, "sel", true },
76d350ecf5Sriastradh 			{}
77d350ecf5Sriastradh 		}, "pgraph_gpc0_tpc0_unk400_pm_mux" },
78d350ecf5Sriastradh 	{}
79d350ecf5Sriastradh };
80d350ecf5Sriastradh 
81d350ecf5Sriastradh static const struct nvkm_specdom
82d350ecf5Sriastradh gf100_pm_hub[] = {
83d350ecf5Sriastradh 	{}
84d350ecf5Sriastradh };
85d350ecf5Sriastradh 
86d350ecf5Sriastradh const struct nvkm_specdom
87d350ecf5Sriastradh gf100_pm_gpc[] = {
88d350ecf5Sriastradh 	{ 0xe0, (const struct nvkm_specsig[]) {
89d350ecf5Sriastradh 			{ 0x00, "gpc00_l1_00", gf100_l1_sources },
90d350ecf5Sriastradh 			{ 0x01, "gpc00_l1_01", gf100_l1_sources },
91d350ecf5Sriastradh 			{ 0x02, "gpc00_l1_02", gf100_l1_sources },
92d350ecf5Sriastradh 			{ 0x03, "gpc00_l1_03", gf100_l1_sources },
93d350ecf5Sriastradh 			{ 0x05, "gpc00_l1_04", gf100_l1_sources },
94d350ecf5Sriastradh 			{ 0x06, "gpc00_l1_05", gf100_l1_sources },
95d350ecf5Sriastradh 			{ 0x0a, "gpc00_tex_00", gf100_tex_sources },
96d350ecf5Sriastradh 			{ 0x0b, "gpc00_tex_01", gf100_tex_sources },
97d350ecf5Sriastradh 			{ 0x0c, "gpc00_tex_02", gf100_tex_sources },
98d350ecf5Sriastradh 			{ 0x0d, "gpc00_tex_03", gf100_tex_sources },
99d350ecf5Sriastradh 			{ 0x0e, "gpc00_tex_04", gf100_tex_sources },
100d350ecf5Sriastradh 			{ 0x0f, "gpc00_tex_05", gf100_tex_sources },
101d350ecf5Sriastradh 			{ 0x10, "gpc00_tex_06", gf100_tex_sources },
102d350ecf5Sriastradh 			{ 0x11, "gpc00_tex_07", gf100_tex_sources },
103d350ecf5Sriastradh 			{ 0x12, "gpc00_tex_08", gf100_tex_sources },
104d350ecf5Sriastradh 			{ 0x26, "gpc00_unk400_00", gf100_unk400_sources },
105d350ecf5Sriastradh 			{}
106d350ecf5Sriastradh 		}, &gf100_perfctr_func },
107d350ecf5Sriastradh 	{}
108d350ecf5Sriastradh };
109d350ecf5Sriastradh 
110*677dec6eSriastradh static const struct nvkm_specdom
111d350ecf5Sriastradh gf100_pm_part[] = {
112d350ecf5Sriastradh 	{ 0xe0, (const struct nvkm_specsig[]) {
113d350ecf5Sriastradh 			{ 0x0f, "part00_pbfb_00", gf100_pbfb_sources },
114d350ecf5Sriastradh 			{ 0x10, "part00_pbfb_01", gf100_pbfb_sources },
115d350ecf5Sriastradh 			{ 0x21, "part00_pmfb_00", gf100_pmfb_sources },
116d350ecf5Sriastradh 			{ 0x04, "part00_pmfb_01", gf100_pmfb_sources },
117d350ecf5Sriastradh 			{ 0x00, "part00_pmfb_02", gf100_pmfb_sources },
118d350ecf5Sriastradh 			{ 0x02, "part00_pmfb_03", gf100_pmfb_sources },
119d350ecf5Sriastradh 			{ 0x01, "part00_pmfb_04", gf100_pmfb_sources },
120d350ecf5Sriastradh 			{ 0x2e, "part00_pmfb_05", gf100_pmfb_sources },
121d350ecf5Sriastradh 			{ 0x2f, "part00_pmfb_06", gf100_pmfb_sources },
122d350ecf5Sriastradh 			{ 0x1b, "part00_pmfb_07", gf100_pmfb_sources },
123d350ecf5Sriastradh 			{ 0x1c, "part00_pmfb_08", gf100_pmfb_sources },
124d350ecf5Sriastradh 			{ 0x1d, "part00_pmfb_09", gf100_pmfb_sources },
125d350ecf5Sriastradh 			{ 0x1e, "part00_pmfb_0a", gf100_pmfb_sources },
126d350ecf5Sriastradh 			{ 0x1f, "part00_pmfb_0b", gf100_pmfb_sources },
127d350ecf5Sriastradh 			{}
128d350ecf5Sriastradh 		}, &gf100_perfctr_func },
129d350ecf5Sriastradh 	{}
130d350ecf5Sriastradh };
131d350ecf5Sriastradh 
132d350ecf5Sriastradh static void
gf100_perfctr_init(struct nvkm_pm * pm,struct nvkm_perfdom * dom,struct nvkm_perfctr * ctr)133d350ecf5Sriastradh gf100_perfctr_init(struct nvkm_pm *pm, struct nvkm_perfdom *dom,
134d350ecf5Sriastradh 		   struct nvkm_perfctr *ctr)
135d350ecf5Sriastradh {
136d350ecf5Sriastradh 	struct nvkm_device *device = pm->engine.subdev.device;
137d350ecf5Sriastradh 	u32 log = ctr->logic_op;
138d350ecf5Sriastradh 	u32 src = 0x00000000;
139d350ecf5Sriastradh 	int i;
140d350ecf5Sriastradh 
141d350ecf5Sriastradh 	for (i = 0; i < 4; i++)
142d350ecf5Sriastradh 		src |= ctr->signal[i] << (i * 8);
143d350ecf5Sriastradh 
144d350ecf5Sriastradh 	nvkm_wr32(device, dom->addr + 0x09c, 0x00040002 | (dom->mode << 3));
145d350ecf5Sriastradh 	nvkm_wr32(device, dom->addr + 0x100, 0x00000000);
146d350ecf5Sriastradh 	nvkm_wr32(device, dom->addr + 0x040 + (ctr->slot * 0x08), src);
147d350ecf5Sriastradh 	nvkm_wr32(device, dom->addr + 0x044 + (ctr->slot * 0x08), log);
148d350ecf5Sriastradh }
149d350ecf5Sriastradh 
150d350ecf5Sriastradh static void
gf100_perfctr_read(struct nvkm_pm * pm,struct nvkm_perfdom * dom,struct nvkm_perfctr * ctr)151d350ecf5Sriastradh gf100_perfctr_read(struct nvkm_pm *pm, struct nvkm_perfdom *dom,
152d350ecf5Sriastradh 		   struct nvkm_perfctr *ctr)
153d350ecf5Sriastradh {
154d350ecf5Sriastradh 	struct nvkm_device *device = pm->engine.subdev.device;
155d350ecf5Sriastradh 
156d350ecf5Sriastradh 	switch (ctr->slot) {
157d350ecf5Sriastradh 	case 0: ctr->ctr = nvkm_rd32(device, dom->addr + 0x08c); break;
158d350ecf5Sriastradh 	case 1: ctr->ctr = nvkm_rd32(device, dom->addr + 0x088); break;
159d350ecf5Sriastradh 	case 2: ctr->ctr = nvkm_rd32(device, dom->addr + 0x080); break;
160d350ecf5Sriastradh 	case 3: ctr->ctr = nvkm_rd32(device, dom->addr + 0x090); break;
161d350ecf5Sriastradh 	}
162d350ecf5Sriastradh 	dom->clk = nvkm_rd32(device, dom->addr + 0x070);
163d350ecf5Sriastradh }
164d350ecf5Sriastradh 
165d350ecf5Sriastradh static void
gf100_perfctr_next(struct nvkm_pm * pm,struct nvkm_perfdom * dom)166d350ecf5Sriastradh gf100_perfctr_next(struct nvkm_pm *pm, struct nvkm_perfdom *dom)
167d350ecf5Sriastradh {
168d350ecf5Sriastradh 	struct nvkm_device *device = pm->engine.subdev.device;
169d350ecf5Sriastradh 	nvkm_wr32(device, dom->addr + 0x06c, dom->signal_nr - 0x40 + 0x27);
170d350ecf5Sriastradh 	nvkm_wr32(device, dom->addr + 0x0ec, 0x00000011);
171d350ecf5Sriastradh }
172d350ecf5Sriastradh 
173d350ecf5Sriastradh const struct nvkm_funcdom
174d350ecf5Sriastradh gf100_perfctr_func = {
175d350ecf5Sriastradh 	.init = gf100_perfctr_init,
176d350ecf5Sriastradh 	.read = gf100_perfctr_read,
177d350ecf5Sriastradh 	.next = gf100_perfctr_next,
178d350ecf5Sriastradh };
179d350ecf5Sriastradh 
180d350ecf5Sriastradh static void
gf100_pm_fini(struct nvkm_pm * pm)181d350ecf5Sriastradh gf100_pm_fini(struct nvkm_pm *pm)
182d350ecf5Sriastradh {
183d350ecf5Sriastradh 	struct nvkm_device *device = pm->engine.subdev.device;
184d350ecf5Sriastradh 	nvkm_mask(device, 0x000200, 0x10000000, 0x00000000);
185d350ecf5Sriastradh 	nvkm_mask(device, 0x000200, 0x10000000, 0x10000000);
186d350ecf5Sriastradh }
187d350ecf5Sriastradh 
188d350ecf5Sriastradh static const struct nvkm_pm_func
189d350ecf5Sriastradh gf100_pm_ = {
190d350ecf5Sriastradh 	.fini = gf100_pm_fini,
191d350ecf5Sriastradh };
192d350ecf5Sriastradh 
193d350ecf5Sriastradh int
gf100_pm_new_(const struct gf100_pm_func * func,struct nvkm_device * device,int index,struct nvkm_pm ** ppm)194d350ecf5Sriastradh gf100_pm_new_(const struct gf100_pm_func *func, struct nvkm_device *device,
195d350ecf5Sriastradh 	      int index, struct nvkm_pm **ppm)
196d350ecf5Sriastradh {
197d350ecf5Sriastradh 	struct nvkm_pm *pm;
198d350ecf5Sriastradh 	u32 mask;
199d350ecf5Sriastradh 	int ret;
200d350ecf5Sriastradh 
201d350ecf5Sriastradh 	if (!(pm = *ppm = kzalloc(sizeof(*pm), GFP_KERNEL)))
202d350ecf5Sriastradh 		return -ENOMEM;
203d350ecf5Sriastradh 
204d350ecf5Sriastradh 	ret = nvkm_pm_ctor(&gf100_pm_, device, index, pm);
205d350ecf5Sriastradh 	if (ret)
206d350ecf5Sriastradh 		return ret;
207d350ecf5Sriastradh 
208d350ecf5Sriastradh 	/* HUB */
209d350ecf5Sriastradh 	ret = nvkm_perfdom_new(pm, "hub", 0, 0x1b0000, 0, 0x200,
210d350ecf5Sriastradh 			       func->doms_hub);
211d350ecf5Sriastradh 	if (ret)
212d350ecf5Sriastradh 		return ret;
213d350ecf5Sriastradh 
214d350ecf5Sriastradh 	/* GPC */
215d350ecf5Sriastradh 	mask  = (1 << nvkm_rd32(device, 0x022430)) - 1;
216d350ecf5Sriastradh 	mask &= ~nvkm_rd32(device, 0x022504);
217d350ecf5Sriastradh 	mask &= ~nvkm_rd32(device, 0x022584);
218d350ecf5Sriastradh 
219d350ecf5Sriastradh 	ret = nvkm_perfdom_new(pm, "gpc", mask, 0x180000,
220d350ecf5Sriastradh 			       0x1000, 0x200, func->doms_gpc);
221d350ecf5Sriastradh 	if (ret)
222d350ecf5Sriastradh 		return ret;
223d350ecf5Sriastradh 
224d350ecf5Sriastradh 	/* PART */
225d350ecf5Sriastradh 	mask  = (1 << nvkm_rd32(device, 0x022438)) - 1;
226d350ecf5Sriastradh 	mask &= ~nvkm_rd32(device, 0x022548);
227d350ecf5Sriastradh 	mask &= ~nvkm_rd32(device, 0x0225c8);
228d350ecf5Sriastradh 
229d350ecf5Sriastradh 	ret = nvkm_perfdom_new(pm, "part", mask, 0x1a0000,
230d350ecf5Sriastradh 			       0x1000, 0x200, func->doms_part);
231d350ecf5Sriastradh 	if (ret)
232d350ecf5Sriastradh 		return ret;
233d350ecf5Sriastradh 
234d350ecf5Sriastradh 	return 0;
235d350ecf5Sriastradh }
236d350ecf5Sriastradh 
237d350ecf5Sriastradh static const struct gf100_pm_func
238d350ecf5Sriastradh gf100_pm = {
239d350ecf5Sriastradh 	.doms_gpc = gf100_pm_gpc,
240d350ecf5Sriastradh 	.doms_hub = gf100_pm_hub,
241d350ecf5Sriastradh 	.doms_part = gf100_pm_part,
242d350ecf5Sriastradh };
243d350ecf5Sriastradh 
244d350ecf5Sriastradh int
gf100_pm_new(struct nvkm_device * device,int index,struct nvkm_pm ** ppm)245d350ecf5Sriastradh gf100_pm_new(struct nvkm_device *device, int index, struct nvkm_pm **ppm)
246d350ecf5Sriastradh {
247d350ecf5Sriastradh 	return gf100_pm_new_(&gf100_pm, device, index, ppm);
248d350ecf5Sriastradh }
249