summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/perf
diff options
context:
space:
mode:
authorVijayakumar Subbu <vsubbu@nvidia.com>2016-07-30 13:44:30 -0400
committerDeepak Nibade <dnibade@nvidia.com>2016-12-27 04:56:49 -0500
commit432017248e432df0619dc2df30f915a52634338f (patch)
tree40bb7a77983fb2753271bc46b346a44ebd6121cf /drivers/gpu/nvgpu/perf
parent38ad90b4840434df4650c617a236e1b01f8a43c6 (diff)
gpu: nvgpu: Add dGPU clocks support
JIRA DNVGPU-42 Change-Id: Ic2fca9d0cf82f2823654ac5e8f0772a1eec7b3b5 Signed-off-by: Vijayakumar Subbu <vsubbu@nvidia.com> Signed-off-by: Terje Bergstrom <tbergstrom@nvidia.com> Reviewed-on: http://git-master/r/1205850 (cherry picked from commit b9f5c6bc4e649162d63e33d65b725872340ca114) Reviewed-on: http://git-master/r/1227257 GVS: Gerrit_Virtual_Submit
Diffstat (limited to 'drivers/gpu/nvgpu/perf')
-rw-r--r--drivers/gpu/nvgpu/perf/perf.c98
-rw-r--r--drivers/gpu/nvgpu/perf/perf.h60
-rw-r--r--drivers/gpu/nvgpu/perf/vfe_equ.c590
-rw-r--r--drivers/gpu/nvgpu/perf/vfe_equ.h76
-rw-r--r--drivers/gpu/nvgpu/perf/vfe_var.c1048
-rw-r--r--drivers/gpu/nvgpu/perf/vfe_var.h97
6 files changed, 1969 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/perf/perf.c b/drivers/gpu/nvgpu/perf/perf.c
new file mode 100644
index 00000000..3821a8dc
--- /dev/null
+++ b/drivers/gpu/nvgpu/perf/perf.c
@@ -0,0 +1,98 @@
1/*
2 * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 */
13
14#include "gk20a/gk20a.h"
15#include "perf.h"
16#include "pmuif/gpmuifperf.h"
17#include "pmuif/gpmuifperfvfe.h"
18#include "gk20a/pmu_gk20a.h"
19
20struct perfrpc_pmucmdhandler_params {
21 struct nv_pmu_perf_rpc *prpccall;
22 u32 success;
23};
24
25static void perfrpc_pmucmdhandler(struct gk20a *g, struct pmu_msg *msg,
26 void *param, u32 handle, u32 status)
27{
28 struct perfrpc_pmucmdhandler_params *phandlerparams =
29 (struct perfrpc_pmucmdhandler_params *)param;
30
31 gk20a_dbg_info("");
32
33 if (msg->msg.perf.msg_type != NV_PMU_PERF_MSG_ID_RPC) {
34 gk20a_err(dev_from_gk20a(g),
35 "unsupported msg for VFE LOAD RPC %x",
36 msg->msg.perf.msg_type);
37 return;
38 }
39
40 if (phandlerparams->prpccall->b_supported)
41 phandlerparams->success = 1;
42}
43
44u32 perf_pmu_vfe_load(struct gk20a *g)
45{
46 struct pmu_cmd cmd;
47 struct pmu_msg msg;
48 struct pmu_payload payload = { {0} };
49 u32 status;
50 u32 seqdesc;
51 struct nv_pmu_perf_rpc rpccall = {0};
52 struct perfrpc_pmucmdhandler_params handler = {0};
53
54 rpccall.function = NV_PMU_PERF_RPC_ID_VFE_LOAD;
55 rpccall.params.vfe_load.b_load = true;
56 cmd.hdr.unit_id = PMU_UNIT_PERF;
57 cmd.hdr.size = (u32)sizeof(struct nv_pmu_perf_cmd) +
58 (u32)sizeof(struct pmu_hdr);
59
60 cmd.cmd.perf.cmd_type = NV_PMU_PERF_CMD_ID_RPC;
61 msg.hdr.size = sizeof(struct pmu_msg);
62
63 payload.in.buf = (u8 *)&rpccall;
64 payload.in.size = (u32)sizeof(struct nv_pmu_perf_rpc);
65 payload.in.fb_size = PMU_CMD_SUBMIT_PAYLOAD_PARAMS_FB_SIZE_UNUSED;
66 payload.in.offset = NV_PMU_PERF_CMD_RPC_ALLOC_OFFSET;
67
68 payload.out.buf = (u8 *)&rpccall;
69 payload.out.size = (u32)sizeof(struct nv_pmu_perf_rpc);
70 payload.out.fb_size = PMU_CMD_SUBMIT_PAYLOAD_PARAMS_FB_SIZE_UNUSED;
71 payload.out.offset = NV_PMU_PERF_MSG_RPC_ALLOC_OFFSET;
72
73 handler.prpccall = &rpccall;
74 handler.success = 0;
75
76 status = gk20a_pmu_cmd_post(g, &cmd, NULL, &payload,
77 PMU_COMMAND_QUEUE_LPQ,
78 perfrpc_pmucmdhandler, (void *)&handler,
79 &seqdesc, ~0);
80
81 if (status) {
82 gk20a_err(dev_from_gk20a(g),
83 "unable to post perf RPC cmd %x",
84 cmd.cmd.perf.cmd_type);
85 goto done;
86 }
87
88 pmu_wait_message_cond(&g->pmu,
89 gk20a_get_gr_idle_timeout(g),
90 &handler.success, 1);
91
92 if (handler.success == 0) {
93 status = -EINVAL;
94 gk20a_err(dev_from_gk20a(g), "rpc call to load VFE failed");
95 }
96done:
97 return status;
98}
diff --git a/drivers/gpu/nvgpu/perf/perf.h b/drivers/gpu/nvgpu/perf/perf.h
new file mode 100644
index 00000000..02aed7a6
--- /dev/null
+++ b/drivers/gpu/nvgpu/perf/perf.h
@@ -0,0 +1,60 @@
1/*
2 * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 */
13#ifndef _PERF_H_
14#define _PERF_H_
15
16#include "vfe_equ.h"
17#include "vfe_var.h"
18#include "gk20a/gk20a.h"
19
20#define CTRL_PERF_VFE_VAR_TYPE_INVALID 0x00
21#define CTRL_PERF_VFE_VAR_TYPE_DERIVED 0x01
22#define CTRL_PERF_VFE_VAR_TYPE_DERIVED_PRODUCT 0x02
23#define CTRL_PERF_VFE_VAR_TYPE_DERIVED_SUM 0x03
24#define CTRL_PERF_VFE_VAR_TYPE_SINGLE 0x04
25#define CTRL_PERF_VFE_VAR_TYPE_SINGLE_FREQUENCY 0x05
26#define CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED 0x06
27#define CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED_FUSE 0x07
28#define CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED_TEMP 0x08
29#define CTRL_PERF_VFE_VAR_TYPE_SINGLE_VOLTAGE 0x09
30
31#define CTRL_PERF_VFE_VAR_SINGLE_OVERRIDE_TYPE_NONE 0x00
32#define CTRL_PERF_VFE_VAR_SINGLE_OVERRIDE_TYPE_VALUE 0x01
33#define CTRL_PERF_VFE_VAR_SINGLE_OVERRIDE_TYPE_OFFSET 0x02
34#define CTRL_PERF_VFE_VAR_SINGLE_OVERRIDE_TYPE_SCALE 0x03
35
36#define CTRL_PERF_VFE_EQU_TYPE_INVALID 0x00
37#define CTRL_PERF_VFE_EQU_TYPE_COMPARE 0x01
38#define CTRL_PERF_VFE_EQU_TYPE_MINMAX 0x02
39#define CTRL_PERF_VFE_EQU_TYPE_QUADRATIC 0x03
40
41#define CTRL_PERF_VFE_EQU_OUTPUT_TYPE_UNITLESS 0x00
42#define CTRL_PERF_VFE_EQU_OUTPUT_TYPE_FREQ_MHZ 0x01
43#define CTRL_PERF_VFE_EQU_OUTPUT_TYPE_VOLT_UV 0x02
44#define CTRL_PERF_VFE_EQU_OUTPUT_TYPE_VF_GAIN 0x03
45#define CTRL_PERF_VFE_EQU_OUTPUT_TYPE_VOLT_DELTA_UV 0x04
46
47#define CTRL_PERF_VFE_EQU_QUADRATIC_COEFF_COUNT 0x03
48
49#define CTRL_PERF_VFE_EQU_COMPARE_FUNCTION_EQUAL 0x00
50#define CTRL_PERF_VFE_EQU_COMPARE_FUNCTION_GREATER_EQ 0x01
51#define CTRL_PERF_VFE_EQU_COMPARE_FUNCTION_GREATER 0x02
52
53struct perf_pmupstate {
54 struct vfe_vars vfe_varobjs;
55 struct vfe_equs vfe_equobjs;
56};
57
58u32 perf_pmu_vfe_load(struct gk20a *g);
59
60#endif
diff --git a/drivers/gpu/nvgpu/perf/vfe_equ.c b/drivers/gpu/nvgpu/perf/vfe_equ.c
new file mode 100644
index 00000000..6630fb21
--- /dev/null
+++ b/drivers/gpu/nvgpu/perf/vfe_equ.c
@@ -0,0 +1,590 @@
1/*
2 * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 */
13
14#include "gk20a/gk20a.h"
15#include "perf.h"
16#include "vfe_equ.h"
17#include "include/bios.h"
18#include "boardobj/boardobjgrp.h"
19#include "boardobj/boardobjgrp_e255.h"
20#include "pmuif/gpmuifboardobj.h"
21#include "pmuif/gpmuifperf.h"
22#include "pmuif/gpmuifperfvfe.h"
23#include "gm206/bios_gm206.h"
24#include "ctrl/ctrlclk.h"
25#include "ctrl/ctrlvolt.h"
26#include "gk20a/pmu_gk20a.h"
27
28static struct vfe_equ *construct_vfe_equ(struct gk20a *g, void *pargs);
29static u32 devinit_get_vfe_equ_table(struct gk20a *g,
30 struct vfe_equs *pequobjs);
31
32static u32 _vfe_equs_pmudatainit(struct gk20a *g,
33 struct boardobjgrp *pboardobjgrp,
34 struct nv_pmu_boardobjgrp_super *pboardobjgrppmu)
35{
36 u32 status = 0;
37
38 status = boardobjgrp_pmudatainit_e255(g, pboardobjgrp, pboardobjgrppmu);
39 if (status) {
40 gk20a_err(dev_from_gk20a(g),
41 "error updating pmu boardobjgrp for vfe equ 0x%x",
42 status);
43 goto done;
44 }
45
46done:
47 return status;
48}
49
50static u32 _vfe_equs_pmudata_instget(struct gk20a *g,
51 struct nv_pmu_boardobjgrp *pmuboardobjgrp,
52 struct nv_pmu_boardobj **ppboardobjpmudata,
53 u8 idx)
54{
55 struct nv_pmu_perf_vfe_equ_boardobj_grp_set *pgrp_set =
56 (struct nv_pmu_perf_vfe_equ_boardobj_grp_set *)pmuboardobjgrp;
57
58 gk20a_dbg_info("");
59
60 /* check whether pmuboardobjgrp has a valid boardobj in index */
61 if (idx >= CTRL_BOARDOBJGRP_E255_MAX_OBJECTS)
62 return -EINVAL;
63
64 *ppboardobjpmudata = (struct nv_pmu_boardobj *)
65 &pgrp_set->objects[idx].data.board_obj;
66 gk20a_dbg_info(" Done");
67 return 0;
68}
69
70u32 vfe_equ_sw_setup(struct gk20a *g)
71{
72 u32 status;
73 struct boardobjgrp *pboardobjgrp = NULL;
74 struct vfe_equs *pvfeequobjs;
75
76 gk20a_dbg_info("");
77
78 status = boardobjgrpconstruct_e255(&g->perf_pmu.vfe_equobjs.super);
79 if (status) {
80 gk20a_err(dev_from_gk20a(g),
81 "error creating boardobjgrp for clk domain, status - 0x%x",
82 status);
83 goto done;
84 }
85
86 pboardobjgrp = &g->perf_pmu.vfe_equobjs.super.super;
87 pvfeequobjs = &(g->perf_pmu.vfe_equobjs);
88
89 BOARDOBJGRP_PMU_CONSTRUCT(pboardobjgrp, PERF, VFE_EQU);
90
91 status = BOARDOBJGRP_PMU_CMD_GRP_SET_CONSTRUCT(g, pboardobjgrp,
92 perf, PERF, vfe_equ, VFE_EQU);
93 if (status) {
94 gk20a_err(dev_from_gk20a(g),
95 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
96 status);
97 goto done;
98 }
99
100 pboardobjgrp->pmudatainit = _vfe_equs_pmudatainit;
101 pboardobjgrp->pmudatainstget = _vfe_equs_pmudata_instget;
102
103 status = devinit_get_vfe_equ_table(g, pvfeequobjs);
104 if (status)
105 goto done;
106
107done:
108 gk20a_dbg_info(" done status %x", status);
109 return status;
110}
111
112u32 vfe_equ_pmu_setup(struct gk20a *g)
113{
114 u32 status;
115 struct boardobjgrp *pboardobjgrp = NULL;
116
117 gk20a_dbg_info("");
118
119 pboardobjgrp = &g->perf_pmu.vfe_equobjs.super.super;
120
121 if (!pboardobjgrp->bconstructed)
122 return -EINVAL;
123
124 status = pboardobjgrp->pmuinithandle(g, pboardobjgrp);
125
126 gk20a_dbg_info("Done");
127 return status;
128}
129
130static u32 devinit_get_vfe_equ_table(struct gk20a *g,
131 struct vfe_equs *pvfeequobjs)
132{
133 u32 status = 0;
134 u8 *vfeequs_tbl_ptr = NULL;
135 struct vbios_vfe_3x_header_struct vfeequs_tbl_header = { 0 };
136 struct vbios_vfe_3x_equ_entry_struct equ = { 0 };
137 u8 *vfeequs_tbl_entry_ptr = NULL;
138 u8 *rd_offset_ptr = NULL;
139 u32 index = 0;
140 struct vfe_equ *pequ;
141 u8 equ_type = 0;
142 u32 szfmt;
143 union {
144 struct boardobj board_obj;
145 struct vfe_equ super;
146 struct vfe_equ_compare compare;
147 struct vfe_equ_minmax minmax;
148 struct vfe_equ_quadratic quadratic;
149 } equ_data;
150
151 gk20a_dbg_info("");
152
153 if (g->ops.bios.get_perf_table_ptrs) {
154 vfeequs_tbl_ptr = (u8 *)g->ops.bios.get_perf_table_ptrs(g,
155 g->bios.perf_token,
156 CONTINUOUS_VIRTUAL_BINNING_TABLE);
157 if (vfeequs_tbl_ptr == NULL) {
158 status = -EINVAL;
159 goto done;
160 }
161 }
162
163 memcpy(&vfeequs_tbl_header, vfeequs_tbl_ptr,
164 VBIOS_CLOCKS_TABLE_1X_HEADER_SIZE_07);
165 if (vfeequs_tbl_header.header_size != VBIOS_CLOCKS_TABLE_1X_HEADER_SIZE_07) {
166 status = -EINVAL;
167 goto done;
168 }
169
170 if (vfeequs_tbl_header.vfe_equ_entry_size ==
171 VBIOS_VFE_3X_EQU_ENTRY_SIZE_17)
172 szfmt = VBIOS_VFE_3X_EQU_ENTRY_SIZE_17;
173 else if (vfeequs_tbl_header.vfe_equ_entry_size ==
174 VBIOS_VFE_3X_EQU_ENTRY_SIZE_18)
175 szfmt = VBIOS_VFE_3X_EQU_ENTRY_SIZE_18;
176 else {
177 status = -EINVAL;
178 goto done;
179 }
180
181 vfeequs_tbl_entry_ptr = vfeequs_tbl_ptr +
182 vfeequs_tbl_header.header_size +
183 (vfeequs_tbl_header.vfe_var_entry_count *
184 vfeequs_tbl_header.vfe_var_entry_size);
185
186 for (index = 0;
187 index < vfeequs_tbl_header.vfe_equ_entry_count;
188 index++) {
189 memset(&equ, 0, sizeof(struct vbios_vfe_3x_equ_entry_struct));
190
191 rd_offset_ptr = vfeequs_tbl_entry_ptr +
192 (index * vfeequs_tbl_header.vfe_equ_entry_size);
193
194 memcpy(&equ, rd_offset_ptr, szfmt);
195
196 equ_data.super.var_idx = (u8)equ.var_idx;
197 equ_data.super.equ_idx_next =
198 (equ.equ_idx_next == VBIOS_VFE_3X_EQU_ENTRY_IDX_INVALID) ?
199 CTRL_BOARDOBJ_IDX_INVALID : (u8)equ.equ_idx_next;
200 equ_data.super.out_range_min = equ.out_range_min;
201 equ_data.super.out_range_max = equ.out_range_max;
202
203 switch (BIOS_GET_FIELD(equ.param3, VBIOS_VFE_3X_EQU_ENTRY_PAR3_OUTPUT_TYPE)) {
204 case VBIOS_VFE_3X_EQU_ENTRY_PAR3_OUTPUT_TYPE_UNITLESS:
205 equ_data.super.output_type =
206 CTRL_PERF_VFE_EQU_OUTPUT_TYPE_UNITLESS;
207 break;
208
209 case VBIOS_VFE_3X_EQU_ENTRY_PAR3_OUTPUT_TYPE_FREQ_MHZ:
210 equ_data.super.output_type =
211 CTRL_PERF_VFE_EQU_OUTPUT_TYPE_FREQ_MHZ;
212 break;
213
214 case VBIOS_VFE_3X_EQU_ENTRY_PAR3_OUTPUT_TYPE_VOLT_UV:
215 equ_data.super.output_type =
216 CTRL_PERF_VFE_EQU_OUTPUT_TYPE_VOLT_UV;
217 break;
218
219 case VBIOS_VFE_3X_EQU_ENTRY_PAR3_OUTPUT_TYPE_VF_GAIN:
220 equ_data.super.output_type =
221 CTRL_PERF_VFE_EQU_OUTPUT_TYPE_VF_GAIN;
222 break;
223
224 case VBIOS_VFE_3X_EQU_ENTRY_PAR3_OUTPUT_TYPE_VOLT_DELTA_UV:
225 equ_data.super.output_type =
226 CTRL_PERF_VFE_EQU_OUTPUT_TYPE_VOLT_DELTA_UV;
227 break;
228
229 default:
230 gk20a_err(dev_from_gk20a(g),
231 "unrecognized output id @vfeequ index %d",
232 index);
233 goto done;
234 }
235
236 switch ((u8)equ.type) {
237 case VBIOS_VFE_3X_EQU_ENTRY_TYPE_DISABLED:
238 case VBIOS_VFE_3X_EQU_ENTRY_TYPE_QUADRATIC_FXP:
239 case VBIOS_VFE_3X_EQU_ENTRY_TYPE_MINMAX_FXP:
240 continue;
241 break;
242
243 case VBIOS_VFE_3X_EQU_ENTRY_TYPE_QUADRATIC:
244 equ_type = CTRL_PERF_VFE_EQU_TYPE_QUADRATIC;
245 equ_data.quadratic.coeffs[0] = equ.param0;
246 equ_data.quadratic.coeffs[1] = equ.param1;
247 equ_data.quadratic.coeffs[2] = equ.param2;
248 break;
249
250 case VBIOS_VFE_3X_EQU_ENTRY_TYPE_MINMAX:
251 equ_type = CTRL_PERF_VFE_EQU_TYPE_MINMAX;
252 equ_data.minmax.b_max = BIOS_GET_FIELD(equ.param0,
253 VBIOS_VFE_3X_EQU_ENTRY_PAR0_MINMAX_CRIT) &&
254 VBIOS_VFE_3X_EQU_ENTRY_PAR0_MINMAX_CRIT_MAX;
255 equ_data.minmax.equ_idx0 = (u8)BIOS_GET_FIELD(
256 equ.param0,
257 VBIOS_VFE_3X_EQU_ENTRY_PAR0_MINMAX_VFE_EQU_IDX_0);
258 equ_data.minmax.equ_idx1 = (u8)BIOS_GET_FIELD(
259 equ.param0,
260 VBIOS_VFE_3X_EQU_ENTRY_PAR0_MINMAX_VFE_EQU_IDX_1);
261 break;
262
263 case VBIOS_VFE_3X_EQU_ENTRY_TYPE_COMPARE:
264 {
265 u8 cmp_func = (u8)BIOS_GET_FIELD(
266 equ.param1,
267 VBIOS_VFE_3X_EQU_ENTRY_PAR1_COMPARE_FUNCTION);
268 equ_type = CTRL_PERF_VFE_EQU_TYPE_COMPARE;
269
270 switch (cmp_func) {
271 case VBIOS_VFE_3X_EQU_ENTRY_PAR1_COMPARE_FUNCTION_EQUAL:
272 equ_data.compare.func_id =
273 CTRL_PERF_VFE_EQU_COMPARE_FUNCTION_EQUAL;
274 break;
275
276 case VBIOS_VFE_3X_EQU_ENTRY_PAR1_COMPARE_FUNCTION_GREATER_EQ:
277 equ_data.compare.func_id =
278 CTRL_PERF_VFE_EQU_COMPARE_FUNCTION_GREATER_EQ;
279 break;
280 case VBIOS_VFE_3X_EQU_ENTRY_PAR1_COMPARE_FUNCTION_GREATER:
281 equ_data.compare.func_id =
282 CTRL_PERF_VFE_EQU_COMPARE_FUNCTION_GREATER;
283 break;
284 default:
285 gk20a_err(dev_from_gk20a(g),
286 "invalid vfe compare index %x type %x ",
287 index, cmp_func);
288 status = -EINVAL;
289 goto done;
290 }
291 equ_data.compare.equ_idx_true = (u8)BIOS_GET_FIELD(
292 equ.param1,
293 VBIOS_VFE_3X_EQU_ENTRY_PAR1_COMPARE_VFE_EQU_IDX_TRUE);
294 equ_data.compare.equ_idx_false = (u8)BIOS_GET_FIELD(
295 equ.param1,
296 VBIOS_VFE_3X_EQU_ENTRY_PAR1_COMPARE_VFE_EQU_IDX_FALSE);
297 equ_data.compare.criteria = equ.param0;
298 break;
299 }
300 default:
301 status = -EINVAL;
302 gk20a_err(dev_from_gk20a(g),
303 "Invalid equ[%d].type = 0x%x.",
304 index, (u8)equ.type);
305 goto done;
306 }
307
308 equ_data.board_obj.type = equ_type;
309 pequ = construct_vfe_equ(g, (void *)&equ_data);
310
311 if (pequ == NULL) {
312 gk20a_err(dev_from_gk20a(g),
313 "error constructing vfe_equ boardobj %d", index);
314 status = -EINVAL;
315 goto done;
316 }
317
318 status = boardobjgrp_objinsert(&pvfeequobjs->super.super,
319 (struct boardobj *)pequ, index);
320 if (status) {
321 gk20a_err(dev_from_gk20a(g),
322 "error adding vfe_equ boardobj %d", index);
323 status = -EINVAL;
324 goto done;
325 }
326 }
327done:
328 gk20a_dbg_info(" done status %x", status);
329 return status;
330}
331
332static u32 _vfe_equ_pmudatainit_super(struct gk20a *g,
333 struct boardobj *board_obj_ptr,
334 struct nv_pmu_boardobj *ppmudata)
335{
336 u32 status = 0;
337 struct vfe_equ *pvfe_equ;
338 struct nv_pmu_vfe_equ *pset;
339
340 gk20a_dbg_info("");
341
342 status = boardobj_pmudatainit_super(g, board_obj_ptr, ppmudata);
343 if (status != 0)
344 return status;
345
346 pvfe_equ = (struct vfe_equ *)board_obj_ptr;
347
348 pset = (struct nv_pmu_vfe_equ *)
349 ppmudata;
350
351 pset->var_idx = pvfe_equ->var_idx;
352 pset->equ_idx_next = pvfe_equ->equ_idx_next;
353 pset->output_type = pvfe_equ->output_type;
354 pset->out_range_min = pvfe_equ->out_range_min;
355 pset->out_range_max = pvfe_equ->out_range_max;
356
357 return status;
358}
359
360static u32 vfe_equ_construct_super(struct gk20a *g,
361 struct boardobj **ppboardobj,
362 u16 size, void *pargs)
363{
364 struct vfe_equ *pvfeequ;
365 struct vfe_equ *ptmpequ = (struct vfe_equ *)pargs;
366 u32 status = 0;
367
368 status = boardobj_construct_super(g, ppboardobj,
369 size, pargs);
370 if (status)
371 return -EINVAL;
372
373 pvfeequ = (struct vfe_equ *)*ppboardobj;
374
375 pvfeequ->super.pmudatainit =
376 _vfe_equ_pmudatainit_super;
377
378 pvfeequ->var_idx = ptmpequ->var_idx;
379 pvfeequ->equ_idx_next = ptmpequ->equ_idx_next;
380 pvfeequ->output_type = ptmpequ->output_type;
381 pvfeequ->out_range_min = ptmpequ->out_range_min;
382 pvfeequ->out_range_max = ptmpequ->out_range_max;
383
384 return status;
385}
386
387static u32 _vfe_equ_pmudatainit_compare(struct gk20a *g,
388 struct boardobj *board_obj_ptr,
389 struct nv_pmu_boardobj *ppmudata)
390{
391 u32 status = 0;
392 struct vfe_equ_compare *pvfe_equ_compare;
393 struct nv_pmu_vfe_equ_compare *pset;
394
395 gk20a_dbg_info("");
396
397 status = _vfe_equ_pmudatainit_super(g, board_obj_ptr, ppmudata);
398 if (status != 0)
399 return status;
400
401 pvfe_equ_compare = (struct vfe_equ_compare *)board_obj_ptr;
402
403 pset = (struct nv_pmu_vfe_equ_compare *) ppmudata;
404
405 pset->func_id = pvfe_equ_compare->func_id;
406 pset->equ_idx_true = pvfe_equ_compare->equ_idx_true;
407 pset->equ_idx_false = pvfe_equ_compare->equ_idx_false;
408 pset->criteria = pvfe_equ_compare->criteria;
409
410 return status;
411}
412
413
414static u32 vfe_equ_construct_compare(struct gk20a *g,
415 struct boardobj **ppboardobj,
416 u16 size, void *pargs)
417{
418 struct boardobj *ptmpobj = (struct boardobj *)pargs;
419 struct vfe_equ_compare *pvfeequ;
420 struct vfe_equ_compare *ptmpequ =
421 (struct vfe_equ_compare *)pargs;
422 u32 status = 0;
423
424 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_PERF_VFE_EQU_TYPE_COMPARE)
425 return -EINVAL;
426
427 ptmpobj->type_mask |= BIT(CTRL_PERF_VFE_EQU_TYPE_COMPARE);
428 status = vfe_equ_construct_super(g, ppboardobj, size, pargs);
429 if (status)
430 return -EINVAL;
431
432 pvfeequ = (struct vfe_equ_compare *)*ppboardobj;
433
434 pvfeequ->super.super.pmudatainit =
435 _vfe_equ_pmudatainit_compare;
436
437 pvfeequ->func_id = ptmpequ->func_id;
438 pvfeequ->equ_idx_true = ptmpequ->equ_idx_true;
439 pvfeequ->equ_idx_false = ptmpequ->equ_idx_false;
440 pvfeequ->criteria = ptmpequ->criteria;
441
442
443 return status;
444}
445
446static u32 _vfe_equ_pmudatainit_minmax(struct gk20a *g,
447 struct boardobj *board_obj_ptr,
448 struct nv_pmu_boardobj *ppmudata)
449{
450 u32 status = 0;
451 struct vfe_equ_minmax *pvfe_equ_minmax;
452 struct nv_pmu_vfe_equ_minmax *pset;
453
454 gk20a_dbg_info("");
455
456 status = _vfe_equ_pmudatainit_super(g, board_obj_ptr, ppmudata);
457 if (status != 0)
458 return status;
459
460 pvfe_equ_minmax = (struct vfe_equ_minmax *)board_obj_ptr;
461
462 pset = (struct nv_pmu_vfe_equ_minmax *)
463 ppmudata;
464
465 pset->b_max = pvfe_equ_minmax->b_max;
466 pset->equ_idx0 = pvfe_equ_minmax->equ_idx0;
467 pset->equ_idx1 = pvfe_equ_minmax->equ_idx1;
468
469 return status;
470}
471
472static u32 vfe_equ_construct_minmax(struct gk20a *g,
473 struct boardobj **ppboardobj,
474 u16 size, void *pargs)
475{
476 struct boardobj *ptmpobj = (struct boardobj *)pargs;
477 struct vfe_equ_minmax *pvfeequ;
478 struct vfe_equ_minmax *ptmpequ =
479 (struct vfe_equ_minmax *)pargs;
480 u32 status = 0;
481
482 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_PERF_VFE_EQU_TYPE_MINMAX)
483 return -EINVAL;
484
485 ptmpobj->type_mask |= BIT(CTRL_PERF_VFE_EQU_TYPE_MINMAX);
486 status = vfe_equ_construct_super(g, ppboardobj, size, pargs);
487 if (status)
488 return -EINVAL;
489
490 pvfeequ = (struct vfe_equ_minmax *)*ppboardobj;
491
492 pvfeequ->super.super.pmudatainit =
493 _vfe_equ_pmudatainit_minmax;
494 pvfeequ->b_max = ptmpequ->b_max;
495 pvfeequ->equ_idx0 = ptmpequ->equ_idx0;
496 pvfeequ->equ_idx1 = ptmpequ->equ_idx1;
497
498 return status;
499}
500
501static u32 _vfe_equ_pmudatainit_quadratic(struct gk20a *g,
502 struct boardobj *board_obj_ptr,
503 struct nv_pmu_boardobj *ppmudata)
504{
505 u32 status = 0;
506 struct vfe_equ_quadratic *pvfe_equ_quadratic;
507 struct nv_pmu_vfe_equ_quadratic *pset;
508 u32 i;
509
510 gk20a_dbg_info("");
511
512 status = _vfe_equ_pmudatainit_super(g, board_obj_ptr, ppmudata);
513 if (status != 0)
514 return status;
515
516 pvfe_equ_quadratic = (struct vfe_equ_quadratic *)board_obj_ptr;
517
518 pset = (struct nv_pmu_vfe_equ_quadratic *) ppmudata;
519
520 for (i = 0; i < CTRL_PERF_VFE_EQU_QUADRATIC_COEFF_COUNT; i++)
521 pset->coeffs[i] = pvfe_equ_quadratic->coeffs[i];
522
523 return status;
524}
525
526static u32 vfe_equ_construct_quadratic(struct gk20a *g,
527 struct boardobj **ppboardobj,
528 u16 size, void *pargs)
529{
530 struct boardobj *ptmpobj = (struct boardobj *)pargs;
531 struct vfe_equ_quadratic *pvfeequ;
532 struct vfe_equ_quadratic *ptmpequ =
533 (struct vfe_equ_quadratic *)pargs;
534 u32 status = 0;
535 u32 i;
536
537 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_PERF_VFE_EQU_TYPE_QUADRATIC)
538 return -EINVAL;
539
540 ptmpobj->type_mask |= BIT(CTRL_PERF_VFE_EQU_TYPE_QUADRATIC);
541 status = vfe_equ_construct_super(g, ppboardobj, size, pargs);
542 if (status)
543 return -EINVAL;
544
545 pvfeequ = (struct vfe_equ_quadratic *)*ppboardobj;
546
547 pvfeequ->super.super.pmudatainit =
548 _vfe_equ_pmudatainit_quadratic;
549
550 for (i = 0; i < CTRL_PERF_VFE_EQU_QUADRATIC_COEFF_COUNT; i++)
551 pvfeequ->coeffs[i] = ptmpequ->coeffs[i];
552
553 return status;
554}
555
556static struct vfe_equ *construct_vfe_equ(struct gk20a *g, void *pargs)
557{
558 struct boardobj *board_obj_ptr = NULL;
559 u32 status;
560
561 gk20a_dbg_info("");
562
563 switch (BOARDOBJ_GET_TYPE(pargs)) {
564 case CTRL_PERF_VFE_EQU_TYPE_COMPARE:
565 status = vfe_equ_construct_compare(g, &board_obj_ptr,
566 sizeof(struct vfe_equ_compare), pargs);
567 break;
568
569 case CTRL_PERF_VFE_EQU_TYPE_MINMAX:
570 status = vfe_equ_construct_minmax(g, &board_obj_ptr,
571 sizeof(struct vfe_equ_minmax), pargs);
572 break;
573
574 case CTRL_PERF_VFE_EQU_TYPE_QUADRATIC:
575 status = vfe_equ_construct_quadratic(g, &board_obj_ptr,
576 sizeof(struct vfe_equ_quadratic), pargs);
577 break;
578
579 default:
580 return NULL;
581
582 }
583
584 if (status)
585 return NULL;
586
587 gk20a_dbg_info(" Done");
588
589 return (struct vfe_equ *)board_obj_ptr;
590}
diff --git a/drivers/gpu/nvgpu/perf/vfe_equ.h b/drivers/gpu/nvgpu/perf/vfe_equ.h
new file mode 100644
index 00000000..8aaddccd
--- /dev/null
+++ b/drivers/gpu/nvgpu/perf/vfe_equ.h
@@ -0,0 +1,76 @@
1/*
2 * general perf structures & definitions
3 *
4 * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 */
15#ifndef _VFE_EQU_H_
16#define _VFE_EQU_H_
17
18#include "boardobj/boardobjgrp.h"
19#include "perf/vfe_var.h"
20#include "pmuif/gpmuifperf.h"
21#include "pmuif/gpmuifperfvfe.h"
22
23u32 vfe_equ_sw_setup(struct gk20a *g);
24u32 vfe_equ_pmu_setup(struct gk20a *g);
25
26#define VFE_EQU_GET(_pperf, _idx) \
27 ((struct vfe_equ *)BOARDOBJGRP_OBJ_GET_BY_IDX( \
28 &((_pperf)->vfe.equs.super.super), (_idx)))
29
30#define VFE_EQU_IDX_IS_VALID(_pperf, _idx) \
31 boardobjgrp_idxisvalid(&((_pperf)->vfe.equs.super.super), (_idx))
32
33#define VFE_EQU_OUTPUT_TYPE_IS_VALID(_pperf, _idx, _outputtype) \
34 (VFE_EQU_IDX_IS_VALID((_pperf), (_idx)) && \
35 ((_outputtype) != CTRL_PERF_VFE_EQU_OUTPUT_TYPE_UNITLESS) && \
36 ((VFE_EQU_GET((_pperf), (_idx))->outputtype == (_outputtype)) || \
37 (VFE_EQU_GET((_pperf), (_idx))->outputtype == \
38 CTRL_PERF_VFE_EQU_OUTPUT_TYPE_UNITLESS)))
39
40struct vfe_equ {
41 struct boardobj super;
42 u8 var_idx;
43 u8 equ_idx_next;
44 u8 output_type;
45 u32 out_range_min;
46 u32 out_range_max;
47
48 bool b_is_dynamic_valid;
49 bool b_is_dynamic;
50};
51
52struct vfe_equs {
53 struct boardobjgrp_e255 super;
54};
55
56struct vfe_equ_compare {
57 struct vfe_equ super;
58 u8 func_id;
59 u8 equ_idx_true;
60 u8 equ_idx_false;
61 u32 criteria;
62};
63
64struct vfe_equ_minmax {
65 struct vfe_equ super;
66 bool b_max;
67 u8 equ_idx0;
68 u8 equ_idx1;
69};
70
71struct vfe_equ_quadratic {
72 struct vfe_equ super;
73 u32 coeffs[CTRL_PERF_VFE_EQU_QUADRATIC_COEFF_COUNT];
74};
75
76#endif
diff --git a/drivers/gpu/nvgpu/perf/vfe_var.c b/drivers/gpu/nvgpu/perf/vfe_var.c
new file mode 100644
index 00000000..90963478
--- /dev/null
+++ b/drivers/gpu/nvgpu/perf/vfe_var.c
@@ -0,0 +1,1048 @@
1/*
2 * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 */
13
14#include "gk20a/gk20a.h"
15#include "perf.h"
16#include "vfe_var.h"
17#include "include/bios.h"
18#include "boardobj/boardobjgrp.h"
19#include "boardobj/boardobjgrp_e32.h"
20#include "pmuif/gpmuifboardobj.h"
21#include "pmuif/gpmuifperf.h"
22#include "pmuif/gpmuifperfvfe.h"
23#include "gm206/bios_gm206.h"
24#include "ctrl/ctrlclk.h"
25#include "ctrl/ctrlvolt.h"
26#include "gk20a/pmu_gk20a.h"
27
28static u32 devinit_get_vfe_var_table(struct gk20a *g,
29 struct vfe_vars *pvarobjs);
30static u32 vfe_var_construct_single(struct gk20a *g,
31 struct boardobj **ppboardobj,
32 u16 size, void *pargs);
33
34static u32 _vfe_vars_pmudatainit(struct gk20a *g,
35 struct boardobjgrp *pboardobjgrp,
36 struct nv_pmu_boardobjgrp_super *pboardobjgrppmu)
37{
38 struct nv_pmu_perf_vfe_var_boardobjgrp_set_header *pset =
39 (struct nv_pmu_perf_vfe_var_boardobjgrp_set_header *)
40 pboardobjgrppmu;
41 struct vfe_vars *pvars = (struct vfe_vars *)pboardobjgrp;
42 u32 status = 0;
43
44 status = boardobjgrp_pmudatainit_e32(g, pboardobjgrp, pboardobjgrppmu);
45 if (status) {
46 gk20a_err(dev_from_gk20a(g),
47 "error updating pmu boardobjgrp for vfe var 0x%x",
48 status);
49 goto done;
50 }
51 pset->polling_periodms = pvars->polling_periodms;
52
53done:
54 return status;
55}
56
57static u32 _vfe_vars_pmudata_instget(struct gk20a *g,
58 struct nv_pmu_boardobjgrp *pmuboardobjgrp,
59 struct nv_pmu_boardobj **ppboardobjpmudata,
60 u8 idx)
61{
62 struct nv_pmu_perf_vfe_var_boardobj_grp_set *pgrp_set =
63 (struct nv_pmu_perf_vfe_var_boardobj_grp_set *)
64 pmuboardobjgrp;
65
66 gk20a_dbg_info("");
67
68 /*check whether pmuboardobjgrp has a valid boardobj in index*/
69 if (idx >= CTRL_BOARDOBJGRP_E32_MAX_OBJECTS)
70 return -EINVAL;
71
72 *ppboardobjpmudata = (struct nv_pmu_boardobj *)
73 &pgrp_set->objects[idx].data.board_obj;
74
75 gk20a_dbg_info(" Done");
76 return 0;
77}
78
79static u32 _vfe_vars_pmustatus_instget(struct gk20a *g, void *pboardobjgrppmu,
80 struct nv_pmu_boardobj_query **ppboardobjpmustatus, u8 idx)
81{
82 struct nv_pmu_perf_vfe_var_boardobj_grp_get_status *pgrp_get_status =
83 (struct nv_pmu_perf_vfe_var_boardobj_grp_get_status *)
84 pboardobjgrppmu;
85
86 if (((u32)BIT(idx) &
87 pgrp_get_status->hdr.data.super.obj_mask.super.data[0]) == 0)
88 return -EINVAL;
89
90 *ppboardobjpmustatus = (struct nv_pmu_boardobj_query *)
91 &pgrp_get_status->objects[idx].data.board_obj;
92 return 0;
93}
94
95
96u32 vfe_var_sw_setup(struct gk20a *g)
97{
98 u32 status;
99 struct boardobjgrp *pboardobjgrp = NULL;
100 struct vfe_vars *pvfevarobjs;
101
102 gk20a_dbg_info("");
103
104 status = boardobjgrpconstruct_e32(&g->perf_pmu.vfe_varobjs.super);
105 if (status) {
106 gk20a_err(dev_from_gk20a(g),
107 "error creating boardobjgrp for clk domain, status - 0x%x",
108 status);
109 goto done;
110 }
111
112 pboardobjgrp = &g->perf_pmu.vfe_varobjs.super.super;
113 pvfevarobjs = &g->perf_pmu.vfe_varobjs;
114
115 BOARDOBJGRP_PMU_CONSTRUCT(pboardobjgrp, PERF, VFE_VAR);
116
117 status = BOARDOBJGRP_PMU_CMD_GRP_SET_CONSTRUCT(g, pboardobjgrp,
118 perf, PERF, vfe_var, VFE_VAR);
119 if (status) {
120 gk20a_err(dev_from_gk20a(g),
121 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
122 status);
123 goto done;
124 }
125
126 pboardobjgrp->pmudatainit = _vfe_vars_pmudatainit;
127 pboardobjgrp->pmudatainstget = _vfe_vars_pmudata_instget;
128 pboardobjgrp->pmustatusinstget = _vfe_vars_pmustatus_instget;
129
130 status = devinit_get_vfe_var_table(g, pvfevarobjs);
131 if (status)
132 goto done;
133
134 status = BOARDOBJGRP_PMU_CMD_GRP_GET_STATUS_CONSTRUCT(g,
135 &g->perf_pmu.vfe_varobjs.super.super,
136 perf, PERF, vfe_var, VFE_VAR);
137 if (status) {
138 gk20a_err(dev_from_gk20a(g),
139 "error constructing PMU_BOARDOBJ_CMD_GRP_GET_STATUS interface - 0x%x",
140 status);
141 goto done;
142 }
143
144done:
145 gk20a_dbg_info(" done status %x", status);
146 return status;
147}
148
149u32 vfe_var_pmu_setup(struct gk20a *g)
150{
151 u32 status;
152 struct boardobjgrp *pboardobjgrp = NULL;
153
154 gk20a_dbg_info("");
155
156 pboardobjgrp = &g->perf_pmu.vfe_varobjs.super.super;
157
158 if (!pboardobjgrp->bconstructed)
159 return -EINVAL;
160
161 status = pboardobjgrp->pmuinithandle(g, pboardobjgrp);
162
163 gk20a_dbg_info("Done");
164 return status;
165}
166
167u32 dev_init_get_vfield_info(struct gk20a *g,
168 struct vfe_var_single_sensed_fuse *pvfevar)
169{
170 u8 *vfieldtableptr = NULL;
171 u32 vfieldheadersize = VFIELD_HEADER_SIZE;
172 u8 *vfieldregtableptr = NULL;
173 u32 vfieldregheadersize = VFIELD_REG_HEADER_SIZE;
174 u32 i;
175 u32 oldindex = 0xFFFFFFFF;
176 u32 currindex;
177 struct vfield_reg_header vregheader;
178 struct vfield_reg_entry vregentry;
179 struct vfield_header vheader;
180 struct vfield_entry ventry;
181 union nv_pmu_bios_vfield_register_segment *psegment = NULL;
182 u8 *psegmentcount = NULL;
183 u32 status = 0;
184
185 if (g->ops.bios.get_perf_table_ptrs) {
186 vfieldregtableptr = (u8 *)g->ops.bios.get_perf_table_ptrs(g,
187 g->bios.virt_token, VP_FIELD_REGISTER);
188 if (vfieldregtableptr == NULL) {
189 status = -EINVAL;
190 goto done;
191 }
192
193 vfieldtableptr = (u8 *)g->ops.bios.get_perf_table_ptrs(g,
194 g->bios.virt_token, VP_FIELD_TABLE);
195 if (vfieldtableptr == NULL) {
196 status = -EINVAL;
197 goto done;
198 }
199 }
200
201 memcpy(&vregheader, vfieldregtableptr, VFIELD_REG_HEADER_SIZE);
202
203 if (vregheader.version != VBIOS_VFIELD_REG_TABLE_VERSION_1_0) {
204 gk20a_err(dev_from_gk20a(g), "invalid vreg header version");
205 goto done;
206 }
207
208 memcpy(&vheader, vfieldtableptr, VFIELD_HEADER_SIZE);
209
210 if (vregheader.version != VBIOS_VFIELD_TABLE_VERSION_1_0) {
211 gk20a_err(dev_from_gk20a(g), "invalid vfield header version");
212 goto done;
213 }
214
215 pvfevar->vfield_info.fuse.segment_count = 0;
216 pvfevar->vfield_ver_info.fuse.segment_count = 0;
217 for (i = 0; i < (u32)vheader.count; i++) {
218 memcpy(&ventry, vfieldtableptr + vfieldheadersize +
219 (i * vheader.entry_size),
220 vheader.entry_size);
221
222 currindex = VFIELD_BIT_REG(ventry);
223 if (currindex != oldindex) {
224
225 memcpy(&vregentry, vfieldregtableptr +
226 vfieldregheadersize +
227 (currindex * vregheader.entry_size),
228 vregheader.entry_size);
229 oldindex = currindex;
230 }
231
232 if (pvfevar->vfield_info.v_field_id == ventry.strap_id) {
233 psegmentcount =
234 &(pvfevar->vfield_info.fuse.segment_count);
235 psegment =
236 &(pvfevar->vfield_info.fuse.segments[*psegmentcount]);
237 if (*psegmentcount > NV_PMU_VFE_VAR_SINGLE_SENSED_FUSE_SEGMENTS_MAX) {
238 status = -EINVAL;
239 goto done;
240 }
241 } else if (pvfevar->vfield_ver_info.v_field_id_ver == ventry.strap_id) {
242 psegmentcount =
243 &(pvfevar->vfield_ver_info.fuse.segment_count);
244 psegment =
245 &(pvfevar->vfield_ver_info.fuse.segments[*psegmentcount]);
246 if (*psegmentcount > NV_PMU_VFE_VAR_SINGLE_SENSED_FUSE_SEGMENTS_MAX) {
247 status = -EINVAL;
248 goto done;
249 }
250 } else {
251 continue;
252 }
253
254 psegment->super.high_bit = (u8)(VFIELD_BIT_STOP(ventry));
255 psegment->super.low_bit = (u8)(VFIELD_BIT_START(ventry));
256 switch (VFIELD_CODE((&vregentry))) {
257 case NV_VFIELD_DESC_CODE_REG:
258 psegment->reg.super.type =
259 NV_PMU_BIOS_VFIELD_DESC_CODE_REG;
260 psegment->reg.addr = vregentry.reg;
261 break;
262
263 case NV_VFIELD_DESC_CODE_INDEX_REG:
264 psegment->index_reg.super.type =
265 NV_PMU_BIOS_VFIELD_DESC_CODE_INDEX_REG;
266 psegment->index_reg.addr = vregentry.reg;
267 psegment->index_reg.index = vregentry.index;
268 psegment->index_reg.reg_index = vregentry.reg_index;
269 break;
270
271 default:
272 psegment->super.type =
273 NV_PMU_BIOS_VFIELD_DESC_CODE_INVALID;
274 status = -EINVAL;
275 goto done;
276 }
277
278 if (VFIELD_SIZE((&vregentry)) != NV_VFIELD_DESC_SIZE_DWORD) {
279 psegment->super.type =
280 NV_PMU_BIOS_VFIELD_DESC_CODE_INVALID;
281 return -EINVAL;
282 }
283 (*psegmentcount)++;
284 }
285
286done:
287
288 return status;
289}
290
291static u32 _vfe_var_pmudatainit_super(struct gk20a *g,
292 struct boardobj *board_obj_ptr,
293 struct nv_pmu_boardobj *ppmudata)
294{
295 u32 status = 0;
296 struct vfe_var *pvfe_var;
297 struct nv_pmu_vfe_var *pset;
298
299 gk20a_dbg_info("");
300
301 status = boardobj_pmudatainit_super(g, board_obj_ptr, ppmudata);
302 if (status != 0)
303 return status;
304
305 pvfe_var = (struct vfe_var *)board_obj_ptr;
306 pset = (struct nv_pmu_vfe_var *) ppmudata;
307
308 pset->out_range_min = pvfe_var->out_range_min;
309 pset->out_range_max = pvfe_var->out_range_max;
310
311 return status;
312}
313
314static u32 vfe_var_construct_super(struct gk20a *g,
315 struct boardobj **ppboardobj,
316 u16 size, void *pargs)
317{
318 struct vfe_var *pvfevar;
319 struct vfe_var *ptmpvar = (struct vfe_var *)pargs;
320 u32 status = 0;
321
322 gk20a_dbg_info("");
323
324 status = boardobj_construct_super(g, ppboardobj, size, pargs);
325 if (status)
326 return -EINVAL;
327
328 pvfevar = (struct vfe_var *)*ppboardobj;
329
330 pvfevar->super.pmudatainit =
331 _vfe_var_pmudatainit_super;
332
333 pvfevar->out_range_min = ptmpvar->out_range_min;
334 pvfevar->out_range_max = ptmpvar->out_range_max;
335 pvfevar->b_is_dynamic_valid = false;
336
337 gk20a_dbg_info("");
338
339 return status;
340}
341
342static u32 _vfe_var_pmudatainit_derived(struct gk20a *g,
343 struct boardobj *board_obj_ptr,
344 struct nv_pmu_boardobj *ppmudata)
345{
346 u32 status = 0;
347
348 gk20a_dbg_info("");
349
350 status = _vfe_var_pmudatainit_super(g, board_obj_ptr, ppmudata);
351
352 return status;
353}
354
355static u32 vfe_var_construct_derived(struct gk20a *g,
356 struct boardobj **ppboardobj,
357 u16 size, void *pargs)
358{
359 struct boardobj *ptmpobj = (struct boardobj *)pargs;
360 u32 status = 0;
361 struct vfe_var_derived *pvfevar;
362
363 ptmpobj->type_mask |= BIT(CTRL_PERF_VFE_VAR_TYPE_DERIVED);
364 status = vfe_var_construct_super(g, ppboardobj, size, pargs);
365 if (status)
366 return -EINVAL;
367
368 pvfevar = (struct vfe_var_derived *)*ppboardobj;
369
370 pvfevar->super.super.pmudatainit =
371 _vfe_var_pmudatainit_derived;
372
373 return status;
374}
375
376static u32 _vfe_var_pmudatainit_derived_product(struct gk20a *g,
377 struct boardobj *board_obj_ptr,
378 struct nv_pmu_boardobj *ppmudata)
379{
380 u32 status = 0;
381 struct vfe_var_derived_product *pvfe_var_derived_product;
382 struct nv_pmu_vfe_var_derived_product *pset;
383
384 gk20a_dbg_info("");
385
386 status = _vfe_var_pmudatainit_derived(g, board_obj_ptr, ppmudata);
387 if (status != 0)
388 return status;
389
390 pvfe_var_derived_product =
391 (struct vfe_var_derived_product *)board_obj_ptr;
392 pset = (struct nv_pmu_vfe_var_derived_product *)ppmudata;
393
394 pset->var_idx0 = pvfe_var_derived_product->var_idx0;
395 pset->var_idx1 = pvfe_var_derived_product->var_idx1;
396
397 return status;
398}
399
400static u32 vfe_var_construct_derived_product(struct gk20a *g,
401 struct boardobj **ppboardobj,
402 u16 size, void *pargs)
403{
404 struct boardobj *ptmpobj = (struct boardobj *)pargs;
405 struct vfe_var_derived_product *pvfevar;
406 struct vfe_var_derived_product *ptmpvar =
407 (struct vfe_var_derived_product *)pargs;
408 u32 status = 0;
409
410 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_PERF_VFE_VAR_TYPE_DERIVED_PRODUCT)
411 return -EINVAL;
412
413 ptmpobj->type_mask |= BIT(CTRL_PERF_VFE_VAR_TYPE_DERIVED_PRODUCT);
414 status = vfe_var_construct_derived(g, ppboardobj, size, pargs);
415 if (status)
416 return -EINVAL;
417
418 pvfevar = (struct vfe_var_derived_product *)*ppboardobj;
419
420 pvfevar->super.super.super.pmudatainit =
421 _vfe_var_pmudatainit_derived_product;
422
423 pvfevar->var_idx0 = ptmpvar->var_idx0;
424 pvfevar->var_idx1 = ptmpvar->var_idx1;
425
426
427 return status;
428}
429
430static u32 _vfe_var_pmudatainit_derived_sum(struct gk20a *g,
431 struct boardobj *board_obj_ptr,
432 struct nv_pmu_boardobj *ppmudata)
433{
434 u32 status = 0;
435 struct vfe_var_derived_sum *pvfe_var_derived_sum;
436 struct nv_pmu_vfe_var_derived_sum *pset;
437
438 gk20a_dbg_info("");
439
440 status = _vfe_var_pmudatainit_derived(g, board_obj_ptr, ppmudata);
441 if (status != 0)
442 return status;
443
444 pvfe_var_derived_sum = (struct vfe_var_derived_sum *)board_obj_ptr;
445 pset = (struct nv_pmu_vfe_var_derived_sum *)ppmudata;
446
447 pset->var_idx0 = pvfe_var_derived_sum->var_idx0;
448 pset->var_idx1 = pvfe_var_derived_sum->var_idx1;
449
450 return status;
451}
452
453static u32 vfe_var_construct_derived_sum(struct gk20a *g,
454 struct boardobj **ppboardobj,
455 u16 size, void *pargs)
456{
457 struct boardobj *ptmpobj = (struct boardobj *)pargs;
458 struct vfe_var_derived_sum *pvfevar;
459 struct vfe_var_derived_sum *ptmpvar =
460 (struct vfe_var_derived_sum *)pargs;
461 u32 status = 0;
462
463 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_PERF_VFE_VAR_TYPE_DERIVED_SUM)
464 return -EINVAL;
465
466 ptmpobj->type_mask |= BIT(CTRL_PERF_VFE_VAR_TYPE_DERIVED_SUM);
467 status = vfe_var_construct_derived(g, ppboardobj, size, pargs);
468 if (status)
469 return -EINVAL;
470
471 pvfevar = (struct vfe_var_derived_sum *)*ppboardobj;
472
473 pvfevar->super.super.super.pmudatainit =
474 _vfe_var_pmudatainit_derived_sum;
475
476 pvfevar->var_idx0 = ptmpvar->var_idx0;
477 pvfevar->var_idx1 = ptmpvar->var_idx1;
478
479 return status;
480}
481
482static u32 _vfe_var_pmudatainit_single(struct gk20a *g,
483 struct boardobj *board_obj_ptr,
484 struct nv_pmu_boardobj *ppmudata)
485{
486 u32 status = 0;
487 struct vfe_var_single *pvfe_var_single;
488 struct nv_pmu_vfe_var_single *pset;
489
490 gk20a_dbg_info("");
491
492 status = _vfe_var_pmudatainit_super(g, board_obj_ptr, ppmudata);
493 if (status != 0)
494 return status;
495
496 pvfe_var_single = (struct vfe_var_single *)board_obj_ptr;
497 pset = (struct nv_pmu_vfe_var_single *)
498 ppmudata;
499
500 pset->override_type = pvfe_var_single->override_type;
501 pset->override_value = pvfe_var_single->override_value;
502
503 return status;
504}
505
506static u32 _vfe_var_pmudatainit_single_frequency(struct gk20a *g,
507 struct boardobj *board_obj_ptr,
508 struct nv_pmu_boardobj *ppmudata)
509{
510 u32 status = 0;
511
512 gk20a_dbg_info("");
513
514 status = _vfe_var_pmudatainit_single(g, board_obj_ptr, ppmudata);
515
516 return status;
517}
518
519static u32 vfe_var_construct_single_frequency(struct gk20a *g,
520 struct boardobj **ppboardobj,
521 u16 size, void *pargs)
522{
523 struct boardobj *ptmpobj = (struct boardobj *)pargs;
524 struct vfe_var_single_frequency *pvfevar;
525 u32 status = 0;
526
527 gk20a_dbg_info("");
528
529 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_PERF_VFE_VAR_TYPE_SINGLE_FREQUENCY)
530 return -EINVAL;
531
532 ptmpobj->type_mask |= BIT(CTRL_PERF_VFE_VAR_TYPE_SINGLE_FREQUENCY);
533 status = vfe_var_construct_single(g, ppboardobj, size, pargs);
534 if (status)
535 return -EINVAL;
536
537 pvfevar = (struct vfe_var_single_frequency *)*ppboardobj;
538
539 pvfevar->super.super.super.pmudatainit =
540 _vfe_var_pmudatainit_single_frequency;
541
542 pvfevar->super.super.b_is_dynamic = false;
543 pvfevar->super.super.b_is_dynamic_valid = true;
544
545 gk20a_dbg_info("Done");
546 return status;
547}
548
549static u32 _vfe_var_pmudatainit_single_sensed(struct gk20a *g,
550 struct boardobj *board_obj_ptr,
551 struct nv_pmu_boardobj *ppmudata)
552{
553 u32 status = 0;
554
555 gk20a_dbg_info("");
556
557 status = _vfe_var_pmudatainit_single(g, board_obj_ptr, ppmudata);
558
559 return status;
560}
561
562static u32 _vfe_var_pmudatainit_single_sensed_fuse(struct gk20a *g,
563 struct boardobj *board_obj_ptr,
564 struct nv_pmu_boardobj *ppmudata)
565{
566 u32 status = 0;
567 struct vfe_var_single_sensed_fuse *pvfe_var_single_sensed_fuse;
568 struct nv_pmu_vfe_var_single_sensed_fuse *pset;
569
570 gk20a_dbg_info("");
571
572 status = _vfe_var_pmudatainit_single_sensed(g, board_obj_ptr, ppmudata);
573 if (status != 0)
574 return status;
575
576 pvfe_var_single_sensed_fuse =
577 (struct vfe_var_single_sensed_fuse *)board_obj_ptr;
578
579 pset = (struct nv_pmu_vfe_var_single_sensed_fuse *)
580 ppmudata;
581
582 memcpy(&pset->vfield_info, &pvfe_var_single_sensed_fuse->vfield_info,
583 sizeof(struct nv_pmu_vfe_var_single_sensed_fuse_vfield_info));
584
585 memcpy(&pset->vfield_ver_info,
586 &pvfe_var_single_sensed_fuse->vfield_ver_info,
587 sizeof(struct nv_pmu_vfe_var_single_sensed_fuse_ver_vfield_info));
588
589 memcpy(&pset->override_info,
590 &pvfe_var_single_sensed_fuse->override_info,
591 sizeof(struct nv_pmu_vfe_var_single_sensed_fuse_override_info));
592
593 return status;
594}
595
596static u32 vfe_var_construct_single_sensed(struct gk20a *g,
597 struct boardobj **ppboardobj,
598 u16 size, void *pargs)
599{
600 struct boardobj *ptmpobj = (struct boardobj *)pargs;
601 struct vfe_var_single_sensed *pvfevar;
602
603 u32 status = 0;
604
605 gk20a_dbg_info(" ");
606
607 ptmpobj->type_mask |= BIT(CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED);
608 status = vfe_var_construct_single(g, ppboardobj, size, pargs);
609 if (status)
610 return -EINVAL;
611
612 pvfevar = (struct vfe_var_single_sensed *)*ppboardobj;
613
614 pvfevar->super.super.super.pmudatainit =
615 _vfe_var_pmudatainit_single_sensed;
616
617 gk20a_dbg_info("Done");
618
619 return status;
620}
621
622static u32 vfe_var_construct_single_sensed_fuse(struct gk20a *g,
623 struct boardobj **ppboardobj,
624 u16 size, void *pargs)
625{
626 struct boardobj *ptmpobj = (struct boardobj *)pargs;
627 struct vfe_var_single_sensed_fuse *pvfevar;
628 struct vfe_var_single_sensed_fuse *ptmpvar =
629 (struct vfe_var_single_sensed_fuse *)pargs;
630 u32 status = 0;
631
632 gk20a_dbg_info("");
633
634 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED_FUSE)
635 return -EINVAL;
636
637 ptmpobj->type_mask |= BIT(CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED_FUSE);
638 status = vfe_var_construct_single_sensed(g, ppboardobj, size, pargs);
639 if (status)
640 return -EINVAL;
641
642 pvfevar = (struct vfe_var_single_sensed_fuse *)*ppboardobj;
643
644 pvfevar->super.super.super.super.pmudatainit =
645 _vfe_var_pmudatainit_single_sensed_fuse;
646
647 pvfevar->vfield_info.v_field_id = ptmpvar->vfield_info.v_field_id;
648 pvfevar->vfield_info.fuse_val_default =
649 ptmpvar->vfield_info.fuse_val_default;
650 pvfevar->vfield_info.hw_correction_scale =
651 ptmpvar->vfield_info.hw_correction_scale;
652 pvfevar->vfield_info.hw_correction_offset =
653 ptmpvar->vfield_info.hw_correction_offset;
654 pvfevar->vfield_ver_info.v_field_id_ver =
655 ptmpvar->vfield_ver_info.v_field_id_ver;
656 pvfevar->vfield_ver_info.ver_expected =
657 ptmpvar->vfield_ver_info.ver_expected;
658 pvfevar->vfield_ver_info.b_use_default_on_ver_check_fail =
659 ptmpvar->vfield_ver_info.b_use_default_on_ver_check_fail;
660 pvfevar->b_version_check_done = false;
661
662 pvfevar->super.super.super.b_is_dynamic = false;
663 pvfevar->super.super.super.b_is_dynamic_valid = true;
664
665 dev_init_get_vfield_info(g, pvfevar);
666 /*check whether fuse segment got initialized*/
667 if (pvfevar->vfield_info.fuse.segment_count == 0) {
668 gk20a_err(dev_from_gk20a(g), "unable to get fuse reg info %x",
669 pvfevar->vfield_info.v_field_id);
670 return -EINVAL;
671 }
672 if (pvfevar->vfield_ver_info.fuse.segment_count == 0) {
673 gk20a_err(dev_from_gk20a(g), "unable to get fuse reg info %x",
674 pvfevar->vfield_ver_info.v_field_id_ver);
675 return -EINVAL;
676 }
677 return status;
678}
679
680static u32 _vfe_var_pmudatainit_single_sensed_temp(struct gk20a *g,
681 struct boardobj *board_obj_ptr,
682 struct nv_pmu_boardobj *ppmudata)
683{
684 u32 status = 0;
685 struct vfe_var_single_sensed_temp *pvfe_var_single_sensed_temp;
686 struct nv_pmu_vfe_var_single_sensed_temp *pset;
687
688 gk20a_dbg_info("");
689
690 status = _vfe_var_pmudatainit_single_sensed(g, board_obj_ptr, ppmudata);
691 if (status != 0)
692 return status;
693
694 pvfe_var_single_sensed_temp =
695 (struct vfe_var_single_sensed_temp *)board_obj_ptr;
696
697 pset = (struct nv_pmu_vfe_var_single_sensed_temp *)
698 ppmudata;
699 pset->therm_channel_index =
700 pvfe_var_single_sensed_temp->therm_channel_index;
701 pset->temp_hysteresis_positive =
702 pvfe_var_single_sensed_temp->temp_hysteresis_positive;
703 pset->temp_hysteresis_negative =
704 pvfe_var_single_sensed_temp->temp_hysteresis_negative;
705 pset->temp_default =
706 pvfe_var_single_sensed_temp->temp_default;
707 return status;
708}
709
710static u32 vfe_var_construct_single_sensed_temp(struct gk20a *g,
711 struct boardobj **ppboardobj,
712 u16 size, void *pargs)
713{
714 struct boardobj *ptmpobj = (struct boardobj *)pargs;
715 struct vfe_var_single_sensed_temp *pvfevar;
716 struct vfe_var_single_sensed_temp *ptmpvar =
717 (struct vfe_var_single_sensed_temp *)pargs;
718 u32 status = 0;
719
720 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED_TEMP)
721 return -EINVAL;
722
723 ptmpobj->type_mask |= BIT(CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED_TEMP);
724 status = vfe_var_construct_single_sensed(g, ppboardobj, size, pargs);
725 if (status)
726 return -EINVAL;
727
728 pvfevar = (struct vfe_var_single_sensed_temp *)*ppboardobj;
729
730 pvfevar->super.super.super.super.pmudatainit =
731 _vfe_var_pmudatainit_single_sensed_temp;
732
733 pvfevar->therm_channel_index =
734 ptmpvar->therm_channel_index;
735 pvfevar->temp_hysteresis_positive =
736 ptmpvar->temp_hysteresis_positive;
737 pvfevar->temp_hysteresis_negative =
738 ptmpvar->temp_hysteresis_negative;
739 pvfevar->temp_default =
740 ptmpvar->temp_default;
741 pvfevar->super.super.super.b_is_dynamic = false;
742 pvfevar->super.super.super.b_is_dynamic_valid = true;
743
744 return status;
745}
746
747static u32 _vfe_var_pmudatainit_single_voltage(struct gk20a *g,
748 struct boardobj *board_obj_ptr,
749 struct nv_pmu_boardobj *ppmudata)
750{
751 u32 status = 0;
752
753 gk20a_dbg_info("");
754
755 status = _vfe_var_pmudatainit_single(g, board_obj_ptr, ppmudata);
756
757 return status;
758}
759
760static u32 vfe_var_construct_single_voltage(struct gk20a *g,
761 struct boardobj **ppboardobj,
762 u16 size, void *pargs)
763{
764 struct boardobj *ptmpobj = (struct boardobj *)pargs;
765 struct vfe_var_single_voltage *pvfevar;
766 u32 status = 0;
767
768 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_PERF_VFE_VAR_TYPE_SINGLE_VOLTAGE)
769 return -EINVAL;
770
771 ptmpobj->type_mask |= BIT(CTRL_PERF_VFE_VAR_TYPE_SINGLE_VOLTAGE);
772 status = vfe_var_construct_super(g, ppboardobj, size, pargs);
773 if (status)
774 return -EINVAL;
775
776 pvfevar = (struct vfe_var_single_voltage *)*ppboardobj;
777
778 pvfevar->super.super.super.pmudatainit =
779 _vfe_var_pmudatainit_single_voltage;
780
781 pvfevar->super.super.b_is_dynamic = false;
782 pvfevar->super.super.b_is_dynamic_valid = true;
783
784 return status;
785}
786
787static struct vfe_var *construct_vfe_var(struct gk20a *g, void *pargs)
788{
789 struct boardobj *board_obj_ptr = NULL;
790 u32 status;
791
792 gk20a_dbg_info("");
793 switch (BOARDOBJ_GET_TYPE(pargs)) {
794 case CTRL_PERF_VFE_VAR_TYPE_DERIVED_PRODUCT:
795 status = vfe_var_construct_derived_product(g, &board_obj_ptr,
796 sizeof(struct vfe_var_derived_product), pargs);
797 break;
798
799 case CTRL_PERF_VFE_VAR_TYPE_DERIVED_SUM:
800 status = vfe_var_construct_derived_sum(g, &board_obj_ptr,
801 sizeof(struct vfe_var_derived_sum), pargs);
802 break;
803
804 case CTRL_PERF_VFE_VAR_TYPE_SINGLE_FREQUENCY:
805 status = vfe_var_construct_single_frequency(g, &board_obj_ptr,
806 sizeof(struct vfe_var_single_frequency), pargs);
807 break;
808
809 case CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED_FUSE:
810 status = vfe_var_construct_single_sensed_fuse(g, &board_obj_ptr,
811 sizeof(struct vfe_var_single_sensed_fuse), pargs);
812 break;
813
814 case CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED_TEMP:
815 status = vfe_var_construct_single_sensed_temp(g, &board_obj_ptr,
816 sizeof(struct vfe_var_single_sensed_temp), pargs);
817 break;
818
819 case CTRL_PERF_VFE_VAR_TYPE_SINGLE_VOLTAGE:
820 status = vfe_var_construct_single_voltage(g, &board_obj_ptr,
821 sizeof(struct vfe_var_single_voltage), pargs);
822 break;
823
824 case CTRL_PERF_VFE_VAR_TYPE_DERIVED:
825 case CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED:
826 case CTRL_PERF_VFE_VAR_TYPE_SINGLE:
827 default:
828 return NULL;
829 }
830
831 if (status)
832 return NULL;
833
834 gk20a_dbg_info("done");
835
836 return (struct vfe_var *)board_obj_ptr;
837}
838
839static u32 devinit_get_vfe_var_table(struct gk20a *g,
840 struct vfe_vars *pvfevarobjs)
841{
842 u32 status = 0;
843 u8 *vfevars_tbl_ptr = NULL;
844 struct vbios_vfe_3x_header_struct vfevars_tbl_header = { 0 };
845 struct vbios_vfe_3x_var_entry_struct var = { 0 };
846 u8 *vfevars_tbl_entry_ptr = NULL;
847 u8 *rd_offset_ptr = NULL;
848 u32 index = 0;
849 struct vfe_var *pvar;
850 u8 var_type;
851 u32 szfmt;
852 union {
853 struct boardobj board_obj;
854 struct vfe_var super;
855 struct vfe_var_derived_product derived_product;
856 struct vfe_var_derived_sum derived_sum;
857 struct vfe_var_single_sensed_fuse single_sensed_fuse;
858 struct vfe_var_single_sensed_temp single_sensed_temp;
859 } var_data;
860
861 gk20a_dbg_info("");
862
863 if (g->ops.bios.get_perf_table_ptrs) {
864 vfevars_tbl_ptr = (u8 *)g->ops.bios.get_perf_table_ptrs(g,
865 g->bios.perf_token,
866 CONTINUOUS_VIRTUAL_BINNING_TABLE);
867 if (vfevars_tbl_ptr == NULL) {
868 status = -EINVAL;
869 goto done;
870 }
871 }
872
873 memcpy(&vfevars_tbl_header, vfevars_tbl_ptr,
874 VBIOS_CLOCKS_TABLE_1X_HEADER_SIZE_07);
875 if (vfevars_tbl_header.header_size !=
876 VBIOS_CLOCKS_TABLE_1X_HEADER_SIZE_07){
877 status = -EINVAL;
878 goto done;
879 }
880
881 if (vfevars_tbl_header.vfe_var_entry_size ==
882 VBIOS_VFE_3X_VAR_ENTRY_SIZE_19)
883 szfmt = VBIOS_VFE_3X_VAR_ENTRY_SIZE_19;
884 else if (vfevars_tbl_header.vfe_var_entry_size ==
885 VBIOS_VFE_3X_VAR_ENTRY_SIZE_11)
886 szfmt = VBIOS_VFE_3X_VAR_ENTRY_SIZE_11;
887 else {
888 status = -EINVAL;
889 goto done;
890 }
891
892 /* Read table entries*/
893 vfevars_tbl_entry_ptr = vfevars_tbl_ptr +
894 vfevars_tbl_header.header_size;
895
896 for (index = 0;
897 index < vfevars_tbl_header.vfe_var_entry_count;
898 index++) {
899 rd_offset_ptr = vfevars_tbl_entry_ptr +
900 (index * vfevars_tbl_header.vfe_var_entry_size);
901 memcpy(&var, rd_offset_ptr, szfmt);
902
903 var_data.super.out_range_min = var.out_range_min;
904 var_data.super.out_range_max = var.out_range_max;
905
906 var_data.super.out_range_min = var.out_range_min;
907 var_data.super.out_range_max = var.out_range_max;
908
909 switch ((u8)var.type) {
910 case VBIOS_VFE_3X_VAR_ENTRY_TYPE_DISABLED:
911 continue;
912 break;
913
914 case VBIOS_VFE_3X_VAR_ENTRY_TYPE_SINGLE_FREQUENCY:
915 var_type = CTRL_PERF_VFE_VAR_TYPE_SINGLE_FREQUENCY;
916 break;
917
918 case VBIOS_VFE_3X_VAR_ENTRY_TYPE_SINGLE_VOLTAGE:
919 var_type = CTRL_PERF_VFE_VAR_TYPE_SINGLE_VOLTAGE;
920 break;
921
922 case VBIOS_VFE_3X_VAR_ENTRY_TYPE_SINGLE_SENSED_TEMP:
923 var_type = CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED_TEMP;
924 var_data.single_sensed_temp.temp_default = 105;
925 var_data.single_sensed_temp.therm_channel_index =
926 (u8)BIOS_GET_FIELD(var.param0,
927 VBIOS_VFE_3X_VAR_ENTRY_PAR0_SSTEMP_TH_CH_IDX);
928 var_data.single_sensed_temp.temp_hysteresis_positive =
929 (u8)BIOS_GET_FIELD(var.param0,
930 VBIOS_VFE_3X_VAR_ENTRY_PAR0_SSTEMP_HYS_POS) << 5;
931 var_data.single_sensed_temp.temp_hysteresis_negative =
932 (u8)BIOS_GET_FIELD(var.param0,
933 VBIOS_VFE_3X_VAR_ENTRY_PAR0_SSTEMP_HYS_NEG) << 5;
934 break;
935
936 case VBIOS_VFE_3X_VAR_ENTRY_TYPE_SINGLE_SENSED_FUSE:
937 var_type = CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED_FUSE;
938 var_data.single_sensed_fuse.vfield_info.v_field_id =
939 (u8)BIOS_GET_FIELD(var.param0,
940 VBIOS_VFE_3X_VAR_ENTRY_PAR0_SSFUSE_VFIELD_ID);
941 var_data.single_sensed_fuse.vfield_ver_info.v_field_id_ver =
942 (u8)BIOS_GET_FIELD(var.param0,
943 VBIOS_VFE_3X_VAR_ENTRY_PAR0_SSFUSE_VFIELD_ID_VER);
944 var_data.single_sensed_fuse.vfield_ver_info.ver_expected =
945 (u8)BIOS_GET_FIELD(var.param0,
946 VBIOS_VFE_3X_VAR_ENTRY_PAR0_SSFUSE_EXPECTED_VER);
947 var_data.single_sensed_fuse.vfield_ver_info.b_use_default_on_ver_check_fail =
948 (BIOS_GET_FIELD(var.param0,
949 VBIOS_VFE_3X_VAR_ENTRY_PAR0_SSFUSE_USE_DEFAULT_ON_VER_CHECK_FAIL) &&
950 VBIOS_VFE_3X_VAR_ENTRY_PAR0_SSFUSE_USE_DEFAULT_ON_VER_CHECK_FAIL_YES);
951 var_data.single_sensed_fuse.vfield_info.fuse_val_default =
952 var.param1;
953 if (szfmt >= VBIOS_VFE_3X_VAR_ENTRY_SIZE_19) {
954 var_data.single_sensed_fuse.vfield_info.hw_correction_scale =
955 (int)var.param2;
956 var_data.single_sensed_fuse.vfield_info.hw_correction_offset =
957 var.param3;
958 } else {
959 var_data.single_sensed_fuse.vfield_info.hw_correction_scale =
960 1 << 12;
961 var_data.single_sensed_fuse.vfield_info.hw_correction_offset =
962 0;
963 if ((var_data.single_sensed_fuse.vfield_info.v_field_id ==
964 VFIELD_ID_STRAP_IDDQ) ||
965 (var_data.single_sensed_fuse.vfield_info.v_field_id ==
966 VFIELD_ID_STRAP_IDDQ_1)) {
967 var_data.single_sensed_fuse.vfield_info.hw_correction_scale =
968 50 << 12;
969 }
970 }
971 break;
972
973 case VBIOS_VFE_3X_VAR_ENTRY_TYPE_DERIVED_PRODUCT:
974 var_type = CTRL_PERF_VFE_VAR_TYPE_DERIVED_PRODUCT;
975 var_data.derived_product.var_idx0 =
976 (u8)BIOS_GET_FIELD(var.param0,
977 VBIOS_VFE_3X_VAR_ENTRY_PAR0_DPROD_VFE_VAR_IDX_0);
978 var_data.derived_product.var_idx1 =
979 (u8)BIOS_GET_FIELD(var.param0,
980 VBIOS_VFE_3X_VAR_ENTRY_PAR0_DPROD_VFE_VAR_IDX_1);
981 break;
982
983 case VBIOS_VFE_3X_VAR_ENTRY_TYPE_DERIVED_SUM:
984 var_type = CTRL_PERF_VFE_VAR_TYPE_DERIVED_SUM;
985 var_data.derived_sum.var_idx0 =
986 (u8)BIOS_GET_FIELD(var.param0,
987 VBIOS_VFE_3X_VAR_ENTRY_PAR0_DSUM_VFE_VAR_IDX_0);
988 var_data.derived_sum.var_idx1 =
989 (u8)BIOS_GET_FIELD(var.param0,
990 VBIOS_VFE_3X_VAR_ENTRY_PAR0_DSUM_VFE_VAR_IDX_1);
991 break;
992 default:
993 status = -EINVAL;
994 goto done;
995 }
996 var_data.board_obj.type = var_type;
997 var_data.board_obj.type_mask = 0;
998
999 pvar = construct_vfe_var(g, &var_data);
1000 if (pvar == NULL) {
1001 gk20a_err(dev_from_gk20a(g),
1002 "error constructing vfe_var boardobj %d",
1003 index);
1004 status = -EINVAL;
1005 goto done;
1006 }
1007
1008 status = boardobjgrp_objinsert(&pvfevarobjs->super.super,
1009 (struct boardobj *)pvar, index);
1010 if (status) {
1011 gk20a_err(dev_from_gk20a(g),
1012 "error adding vfe_var boardobj %d", index);
1013 status = -EINVAL;
1014 goto done;
1015 }
1016 }
1017 pvfevarobjs->polling_periodms = vfevars_tbl_header.polling_periodms;
1018done:
1019 gk20a_dbg_info("done status %x", status);
1020 return status;
1021}
1022
1023static u32 vfe_var_construct_single(struct gk20a *g,
1024 struct boardobj **ppboardobj,
1025 u16 size, void *pargs)
1026{
1027 struct boardobj *ptmpobj = (struct boardobj *)pargs;
1028 struct vfe_var_single *pvfevar;
1029 u32 status = 0;
1030
1031 gk20a_dbg_info("");
1032
1033 ptmpobj->type_mask |= BIT(CTRL_PERF_VFE_VAR_TYPE_SINGLE);
1034 status = vfe_var_construct_super(g, ppboardobj, size, pargs);
1035 if (status)
1036 return -EINVAL;
1037
1038 pvfevar = (struct vfe_var_single *)*ppboardobj;
1039
1040 pvfevar->super.super.pmudatainit =
1041 _vfe_var_pmudatainit_single;
1042
1043 pvfevar->override_type = CTRL_PERF_VFE_VAR_SINGLE_OVERRIDE_TYPE_NONE;
1044 pvfevar->override_value = 0;
1045
1046 gk20a_dbg_info("Done");
1047 return status;
1048}
diff --git a/drivers/gpu/nvgpu/perf/vfe_var.h b/drivers/gpu/nvgpu/perf/vfe_var.h
new file mode 100644
index 00000000..fc43311b
--- /dev/null
+++ b/drivers/gpu/nvgpu/perf/vfe_var.h
@@ -0,0 +1,97 @@
1/*
2 * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 */
13
14#ifndef _VFE_VAR_H_
15#define _VFE_VAR_H_
16
17#include "boardobj/boardobjgrp.h"
18#include "pmuif/gpmuifperf.h"
19#include "pmuif/gpmuifperfvfe.h"
20
21u32 vfe_var_sw_setup(struct gk20a *g);
22u32 vfe_var_pmu_setup(struct gk20a *g);
23
24#define VFE_VAR_GET(_pperf, _idx) \
25 ((struct vfe_var)BOARDOBJGRP_OBJ_GET_BY_IDX( \
26 &((_pperf)->vfe.vars.super.super), (_idx)))
27
28#define VFE_VAR_IDX_IS_VALID(_pperf, _idx) \
29 boardobjgrp_idxisvalid(&((_pperf)->vfe.vars.super.super), (_idx))
30
31struct vfe_var {
32 struct boardobj super;
33 u32 out_range_min;
34 u32 out_range_max;
35 bool b_is_dynamic_valid;
36 bool b_is_dynamic;
37};
38
39struct vfe_vars {
40 struct boardobjgrp_e32 super;
41 u8 polling_periodms;
42};
43
44struct vfe_var_derived {
45 struct vfe_var super;
46};
47
48struct vfe_var_derived_product {
49 struct vfe_var_derived super;
50 u8 var_idx0;
51 u8 var_idx1;
52};
53
54struct vfe_var_derived_sum {
55 struct vfe_var_derived super;
56 u8 var_idx0;
57 u8 var_idx1;
58};
59
60struct vfe_var_single {
61 struct vfe_var super;
62 u8 override_type;
63 u32 override_value;
64};
65
66struct vfe_var_single_frequency {
67 struct vfe_var_single super;
68};
69
70struct vfe_var_single_voltage {
71 struct vfe_var_single super;
72};
73
74struct vfe_var_single_sensed {
75 struct vfe_var_single super;
76};
77
78struct vfe_var_single_sensed_fuse {
79 struct vfe_var_single_sensed super;
80 struct nv_pmu_vfe_var_single_sensed_fuse_override_info override_info;
81 struct nv_pmu_vfe_var_single_sensed_fuse_vfield_info vfield_info;
82 struct nv_pmu_vfe_var_single_sensed_fuse_ver_vfield_info vfield_ver_info;
83 u32 fuse_value_integer;
84 u32 fuse_value_hw_integer;
85 u8 fuse_version;
86 bool b_version_check_done;
87};
88
89struct vfe_var_single_sensed_temp {
90 struct vfe_var_single_sensed super;
91 u8 therm_channel_index;
92 int temp_hysteresis_positive;
93 int temp_hysteresis_negative;
94 int temp_default;
95};
96
97#endif