1 /*
2  * Copyright 2013 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: Ben Skeggs
23  */
24 
25 #include "nv40.h"
26 
27 /*******************************************************************************
28  * Perfmon object classes
29  ******************************************************************************/
30 
31 /*******************************************************************************
32  * PPM context
33  ******************************************************************************/
34 
35 /*******************************************************************************
36  * PPM engine/subdev functions
37  ******************************************************************************/
38 
39 static void
40 nv40_perfctr_init(struct nouveau_pm *ppm, struct nouveau_perfdom *dom,
41 		  struct nouveau_perfctr *ctr)
42 {
43 	struct nv40_pm_priv *priv = (void *)ppm;
44 	struct nv40_pm_cntr *cntr = (void *)ctr;
45 	u32 log = ctr->logic_op;
46 	u32 src = 0x00000000;
47 	int i;
48 
49 	for (i = 0; i < 4 && ctr->signal[i]; i++)
50 		src |= (ctr->signal[i] - dom->signal) << (i * 8);
51 
52 	nv_wr32(priv, 0x00a7c0 + dom->addr, 0x00000001);
53 	nv_wr32(priv, 0x00a400 + dom->addr + (cntr->base.slot * 0x40), src);
54 	nv_wr32(priv, 0x00a420 + dom->addr + (cntr->base.slot * 0x40), log);
55 }
56 
57 static void
58 nv40_perfctr_read(struct nouveau_pm *ppm, struct nouveau_perfdom *dom,
59 		  struct nouveau_perfctr *ctr)
60 {
61 	struct nv40_pm_priv *priv = (void *)ppm;
62 	struct nv40_pm_cntr *cntr = (void *)ctr;
63 
64 	switch (cntr->base.slot) {
65 	case 0: cntr->base.ctr = nv_rd32(priv, 0x00a700 + dom->addr); break;
66 	case 1: cntr->base.ctr = nv_rd32(priv, 0x00a6c0 + dom->addr); break;
67 	case 2: cntr->base.ctr = nv_rd32(priv, 0x00a680 + dom->addr); break;
68 	case 3: cntr->base.ctr = nv_rd32(priv, 0x00a740 + dom->addr); break;
69 	}
70 	cntr->base.clk = nv_rd32(priv, 0x00a600 + dom->addr);
71 }
72 
73 static void
74 nv40_perfctr_next(struct nouveau_pm *ppm, struct nouveau_perfdom *dom)
75 {
76 	struct nv40_pm_priv *priv = (void *)ppm;
77 	if (priv->sequence != ppm->sequence) {
78 		nv_wr32(priv, 0x400084, 0x00000020);
79 		priv->sequence = ppm->sequence;
80 	}
81 }
82 
83 const struct nouveau_funcdom
84 nv40_perfctr_func = {
85 	.init = nv40_perfctr_init,
86 	.read = nv40_perfctr_read,
87 	.next = nv40_perfctr_next,
88 };
89 
90 static const struct nouveau_specdom
91 nv40_pm[] = {
92 	{ 0x20, (const struct nouveau_specsig[]) {
93 			{}
94 		}, &nv40_perfctr_func },
95 	{ 0x20, (const struct nouveau_specsig[]) {
96 			{}
97 		}, &nv40_perfctr_func },
98 	{ 0x20, (const struct nouveau_specsig[]) {
99 			{}
100 		}, &nv40_perfctr_func },
101 	{ 0x20, (const struct nouveau_specsig[]) {
102 			{}
103 		}, &nv40_perfctr_func },
104 	{ 0x20, (const struct nouveau_specsig[]) {
105 			{}
106 		}, &nv40_perfctr_func },
107 	{}
108 };
109 
110 int
111 nv40_pm_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
112 		  struct nouveau_oclass *oclass, void *data, u32 size,
113 		  struct nouveau_object **pobject)
114 {
115 	struct nv40_pm_oclass *mclass = (void *)oclass;
116 	struct nv40_pm_priv *priv;
117 	int ret;
118 
119 	ret = nouveau_pm_create(parent, engine, oclass, &priv);
120 	*pobject = nv_object(priv);
121 	if (ret)
122 		return ret;
123 
124 	ret = nouveau_perfdom_new(&priv->base, "pm", 0, 0, 0, 4, mclass->doms);
125 	if (ret)
126 		return ret;
127 
128 	nv_engine(priv)->cclass = &nouveau_pm_cclass;
129 	nv_engine(priv)->sclass =  nouveau_pm_sclass;
130 	return 0;
131 }
132 
133 struct nouveau_oclass *
134 nv40_pm_oclass = &(struct nv40_pm_oclass) {
135 	.base.handle = NV_ENGINE(PM, 0x40),
136 	.base.ofuncs = &(struct nouveau_ofuncs) {
137 		.ctor = nv40_pm_ctor,
138 		.dtor = _nouveau_pm_dtor,
139 		.init = _nouveau_pm_init,
140 		.fini = _nouveau_pm_fini,
141 	},
142 	.doms = nv40_pm,
143 }.base;
144