summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/perf/vfe_var.c
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/vfe_var.c
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/vfe_var.c')
-rw-r--r--drivers/gpu/nvgpu/perf/vfe_var.c1048
1 files changed, 1048 insertions, 0 deletions
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}