summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/perf/vfe_var.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/nvgpu/perf/vfe_var.c')
-rw-r--r--drivers/gpu/nvgpu/perf/vfe_var.c1054
1 files changed, 1054 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..c46747c9
--- /dev/null
+++ b/drivers/gpu/nvgpu/perf/vfe_var.c
@@ -0,0 +1,1054 @@
1/*
2 * Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
21 */
22
23#include <nvgpu/bios.h>
24
25#include "gk20a/gk20a.h"
26#include "perf.h"
27#include "vfe_var.h"
28#include "boardobj/boardobjgrp.h"
29#include "boardobj/boardobjgrp_e32.h"
30#include "ctrl/ctrlclk.h"
31#include "ctrl/ctrlvolt.h"
32
33static u32 devinit_get_vfe_var_table(struct gk20a *g,
34 struct vfe_vars *pvarobjs);
35static u32 vfe_var_construct_single(struct gk20a *g,
36 struct boardobj **ppboardobj,
37 u16 size, void *pargs);
38
39static u32 _vfe_vars_pmudatainit(struct gk20a *g,
40 struct boardobjgrp *pboardobjgrp,
41 struct nv_pmu_boardobjgrp_super *pboardobjgrppmu)
42{
43 struct nv_pmu_perf_vfe_var_boardobjgrp_set_header *pset =
44 (struct nv_pmu_perf_vfe_var_boardobjgrp_set_header *)
45 pboardobjgrppmu;
46 struct vfe_vars *pvars = (struct vfe_vars *)pboardobjgrp;
47 u32 status = 0;
48
49 status = boardobjgrp_pmudatainit_e32(g, pboardobjgrp, pboardobjgrppmu);
50 if (status) {
51 nvgpu_err(g,
52 "error updating pmu boardobjgrp for vfe var 0x%x",
53 status);
54 goto done;
55 }
56 pset->polling_periodms = pvars->polling_periodms;
57
58done:
59 return status;
60}
61
62static u32 _vfe_vars_pmudata_instget(struct gk20a *g,
63 struct nv_pmu_boardobjgrp *pmuboardobjgrp,
64 struct nv_pmu_boardobj **ppboardobjpmudata,
65 u8 idx)
66{
67 struct nv_pmu_perf_vfe_var_boardobj_grp_set *pgrp_set =
68 (struct nv_pmu_perf_vfe_var_boardobj_grp_set *)
69 pmuboardobjgrp;
70
71 gk20a_dbg_info("");
72
73 /*check whether pmuboardobjgrp has a valid boardobj in index*/
74 if (idx >= CTRL_BOARDOBJGRP_E32_MAX_OBJECTS)
75 return -EINVAL;
76
77 *ppboardobjpmudata = (struct nv_pmu_boardobj *)
78 &pgrp_set->objects[idx].data.board_obj;
79
80 gk20a_dbg_info(" Done");
81 return 0;
82}
83
84static u32 _vfe_vars_pmustatus_instget(struct gk20a *g, void *pboardobjgrppmu,
85 struct nv_pmu_boardobj_query **ppboardobjpmustatus, u8 idx)
86{
87 struct nv_pmu_perf_vfe_var_boardobj_grp_get_status *pgrp_get_status =
88 (struct nv_pmu_perf_vfe_var_boardobj_grp_get_status *)
89 pboardobjgrppmu;
90
91 if (((u32)BIT(idx) &
92 pgrp_get_status->hdr.data.super.obj_mask.super.data[0]) == 0)
93 return -EINVAL;
94
95 *ppboardobjpmustatus = (struct nv_pmu_boardobj_query *)
96 &pgrp_get_status->objects[idx].data.board_obj;
97 return 0;
98}
99
100
101u32 vfe_var_sw_setup(struct gk20a *g)
102{
103 u32 status;
104 struct boardobjgrp *pboardobjgrp = NULL;
105 struct vfe_vars *pvfevarobjs;
106
107 gk20a_dbg_info("");
108
109 status = boardobjgrpconstruct_e32(g, &g->perf_pmu.vfe_varobjs.super);
110 if (status) {
111 nvgpu_err(g,
112 "error creating boardobjgrp for clk domain, status - 0x%x",
113 status);
114 goto done;
115 }
116
117 pboardobjgrp = &g->perf_pmu.vfe_varobjs.super.super;
118 pvfevarobjs = &g->perf_pmu.vfe_varobjs;
119
120 BOARDOBJGRP_PMU_CONSTRUCT(pboardobjgrp, PERF, VFE_VAR);
121
122 status = BOARDOBJGRP_PMU_CMD_GRP_SET_CONSTRUCT(g, pboardobjgrp,
123 perf, PERF, vfe_var, VFE_VAR);
124 if (status) {
125 nvgpu_err(g,
126 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
127 status);
128 goto done;
129 }
130
131 pboardobjgrp->pmudatainit = _vfe_vars_pmudatainit;
132 pboardobjgrp->pmudatainstget = _vfe_vars_pmudata_instget;
133 pboardobjgrp->pmustatusinstget = _vfe_vars_pmustatus_instget;
134
135 status = devinit_get_vfe_var_table(g, pvfevarobjs);
136 if (status)
137 goto done;
138
139 status = BOARDOBJGRP_PMU_CMD_GRP_GET_STATUS_CONSTRUCT(g,
140 &g->perf_pmu.vfe_varobjs.super.super,
141 perf, PERF, vfe_var, VFE_VAR);
142 if (status) {
143 nvgpu_err(g,
144 "error constructing PMU_BOARDOBJ_CMD_GRP_GET_STATUS interface - 0x%x",
145 status);
146 goto done;
147 }
148
149done:
150 gk20a_dbg_info(" done status %x", status);
151 return status;
152}
153
154u32 vfe_var_pmu_setup(struct gk20a *g)
155{
156 u32 status;
157 struct boardobjgrp *pboardobjgrp = NULL;
158
159 gk20a_dbg_info("");
160
161 pboardobjgrp = &g->perf_pmu.vfe_varobjs.super.super;
162
163 if (!pboardobjgrp->bconstructed)
164 return -EINVAL;
165
166 status = pboardobjgrp->pmuinithandle(g, pboardobjgrp);
167
168 gk20a_dbg_info("Done");
169 return status;
170}
171
172static u32 dev_init_get_vfield_info(struct gk20a *g,
173 struct vfe_var_single_sensed_fuse *pvfevar)
174{
175 u8 *vfieldtableptr = NULL;
176 u32 vfieldheadersize = VFIELD_HEADER_SIZE;
177 u8 *vfieldregtableptr = NULL;
178 u32 vfieldregheadersize = VFIELD_REG_HEADER_SIZE;
179 u32 i;
180 u32 oldindex = 0xFFFFFFFF;
181 u32 currindex;
182 struct vfield_reg_header vregheader;
183 struct vfield_reg_entry vregentry;
184 struct vfield_header vheader;
185 struct vfield_entry ventry;
186 union nv_pmu_bios_vfield_register_segment *psegment = NULL;
187 u8 *psegmentcount = NULL;
188 u32 status = 0;
189
190 vfieldregtableptr = (u8 *)nvgpu_bios_get_perf_table_ptrs(g,
191 g->bios.virt_token, VP_FIELD_REGISTER);
192 if (vfieldregtableptr == NULL) {
193 status = -EINVAL;
194 goto done;
195 }
196
197 vfieldtableptr = (u8 *)nvgpu_bios_get_perf_table_ptrs(g,
198 g->bios.virt_token, VP_FIELD_TABLE);
199 if (vfieldtableptr == NULL) {
200 status = -EINVAL;
201 goto done;
202 }
203
204 memcpy(&vregheader, vfieldregtableptr, VFIELD_REG_HEADER_SIZE);
205
206 if (vregheader.version != VBIOS_VFIELD_REG_TABLE_VERSION_1_0) {
207 nvgpu_err(g, "invalid vreg header version");
208 goto done;
209 }
210
211 memcpy(&vheader, vfieldtableptr, VFIELD_HEADER_SIZE);
212
213 if (vregheader.version != VBIOS_VFIELD_TABLE_VERSION_1_0) {
214 nvgpu_err(g, "invalid vfield header version");
215 goto done;
216 }
217
218 pvfevar->vfield_info.fuse.segment_count = 0;
219 pvfevar->vfield_ver_info.fuse.segment_count = 0;
220 for (i = 0; i < (u32)vheader.count; i++) {
221 memcpy(&ventry, vfieldtableptr + vfieldheadersize +
222 (i * vheader.entry_size),
223 vheader.entry_size);
224
225 currindex = VFIELD_BIT_REG(ventry);
226 if (currindex != oldindex) {
227
228 memcpy(&vregentry, vfieldregtableptr +
229 vfieldregheadersize +
230 (currindex * vregheader.entry_size),
231 vregheader.entry_size);
232 oldindex = currindex;
233 }
234
235 if (pvfevar->vfield_info.v_field_id == ventry.strap_id) {
236 psegmentcount =
237 &(pvfevar->vfield_info.fuse.segment_count);
238 psegment =
239 &(pvfevar->vfield_info.fuse.segments[*psegmentcount]);
240 if (*psegmentcount > NV_PMU_VFE_VAR_SINGLE_SENSED_FUSE_SEGMENTS_MAX) {
241 status = -EINVAL;
242 goto done;
243 }
244 } else if (pvfevar->vfield_ver_info.v_field_id_ver == ventry.strap_id) {
245 psegmentcount =
246 &(pvfevar->vfield_ver_info.fuse.segment_count);
247 psegment =
248 &(pvfevar->vfield_ver_info.fuse.segments[*psegmentcount]);
249 if (*psegmentcount > NV_PMU_VFE_VAR_SINGLE_SENSED_FUSE_SEGMENTS_MAX) {
250 status = -EINVAL;
251 goto done;
252 }
253 } else {
254 continue;
255 }
256
257 psegment->super.high_bit = (u8)(VFIELD_BIT_STOP(ventry));
258 psegment->super.low_bit = (u8)(VFIELD_BIT_START(ventry));
259 switch (VFIELD_CODE((&vregentry))) {
260 case NV_VFIELD_DESC_CODE_REG:
261 psegment->reg.super.type =
262 NV_PMU_BIOS_VFIELD_DESC_CODE_REG;
263 psegment->reg.addr = vregentry.reg;
264 break;
265
266 case NV_VFIELD_DESC_CODE_INDEX_REG:
267 psegment->index_reg.super.type =
268 NV_PMU_BIOS_VFIELD_DESC_CODE_INDEX_REG;
269 psegment->index_reg.addr = vregentry.reg;
270 psegment->index_reg.index = vregentry.index;
271 psegment->index_reg.reg_index = vregentry.reg_index;
272 break;
273
274 default:
275 psegment->super.type =
276 NV_PMU_BIOS_VFIELD_DESC_CODE_INVALID;
277 status = -EINVAL;
278 goto done;
279 }
280
281 if (VFIELD_SIZE((&vregentry)) != NV_VFIELD_DESC_SIZE_DWORD) {
282 psegment->super.type =
283 NV_PMU_BIOS_VFIELD_DESC_CODE_INVALID;
284 return -EINVAL;
285 }
286 (*psegmentcount)++;
287 }
288
289done:
290
291 return status;
292}
293
294static u32 _vfe_var_pmudatainit_super(struct gk20a *g,
295 struct boardobj *board_obj_ptr,
296 struct nv_pmu_boardobj *ppmudata)
297{
298 u32 status = 0;
299 struct vfe_var *pvfe_var;
300 struct nv_pmu_vfe_var *pset;
301
302 gk20a_dbg_info("");
303
304 status = boardobj_pmudatainit_super(g, board_obj_ptr, ppmudata);
305 if (status != 0)
306 return status;
307
308 pvfe_var = (struct vfe_var *)board_obj_ptr;
309 pset = (struct nv_pmu_vfe_var *) ppmudata;
310
311 pset->out_range_min = pvfe_var->out_range_min;
312 pset->out_range_max = pvfe_var->out_range_max;
313
314 return status;
315}
316
317static u32 vfe_var_construct_super(struct gk20a *g,
318 struct boardobj **ppboardobj,
319 u16 size, void *pargs)
320{
321 struct vfe_var *pvfevar;
322 struct vfe_var *ptmpvar = (struct vfe_var *)pargs;
323 u32 status = 0;
324
325 gk20a_dbg_info("");
326
327 status = boardobj_construct_super(g, ppboardobj, size, pargs);
328 if (status)
329 return -EINVAL;
330
331 pvfevar = (struct vfe_var *)*ppboardobj;
332
333 pvfevar->super.pmudatainit =
334 _vfe_var_pmudatainit_super;
335
336 pvfevar->out_range_min = ptmpvar->out_range_min;
337 pvfevar->out_range_max = ptmpvar->out_range_max;
338 pvfevar->b_is_dynamic_valid = false;
339
340 gk20a_dbg_info("");
341
342 return status;
343}
344
345static u32 _vfe_var_pmudatainit_derived(struct gk20a *g,
346 struct boardobj *board_obj_ptr,
347 struct nv_pmu_boardobj *ppmudata)
348{
349 u32 status = 0;
350
351 gk20a_dbg_info("");
352
353 status = _vfe_var_pmudatainit_super(g, board_obj_ptr, ppmudata);
354
355 return status;
356}
357
358static u32 vfe_var_construct_derived(struct gk20a *g,
359 struct boardobj **ppboardobj,
360 u16 size, void *pargs)
361{
362 struct boardobj *ptmpobj = (struct boardobj *)pargs;
363 u32 status = 0;
364 struct vfe_var_derived *pvfevar;
365
366 ptmpobj->type_mask |= BIT(CTRL_PERF_VFE_VAR_TYPE_DERIVED);
367 status = vfe_var_construct_super(g, ppboardobj, size, pargs);
368 if (status)
369 return -EINVAL;
370
371 pvfevar = (struct vfe_var_derived *)*ppboardobj;
372
373 pvfevar->super.super.pmudatainit =
374 _vfe_var_pmudatainit_derived;
375
376 return status;
377}
378
379static u32 _vfe_var_pmudatainit_derived_product(struct gk20a *g,
380 struct boardobj *board_obj_ptr,
381 struct nv_pmu_boardobj *ppmudata)
382{
383 u32 status = 0;
384 struct vfe_var_derived_product *pvfe_var_derived_product;
385 struct nv_pmu_vfe_var_derived_product *pset;
386
387 gk20a_dbg_info("");
388
389 status = _vfe_var_pmudatainit_derived(g, board_obj_ptr, ppmudata);
390 if (status != 0)
391 return status;
392
393 pvfe_var_derived_product =
394 (struct vfe_var_derived_product *)board_obj_ptr;
395 pset = (struct nv_pmu_vfe_var_derived_product *)ppmudata;
396
397 pset->var_idx0 = pvfe_var_derived_product->var_idx0;
398 pset->var_idx1 = pvfe_var_derived_product->var_idx1;
399
400 return status;
401}
402
403static u32 vfe_var_construct_derived_product(struct gk20a *g,
404 struct boardobj **ppboardobj,
405 u16 size, void *pargs)
406{
407 struct boardobj *ptmpobj = (struct boardobj *)pargs;
408 struct vfe_var_derived_product *pvfevar;
409 struct vfe_var_derived_product *ptmpvar =
410 (struct vfe_var_derived_product *)pargs;
411 u32 status = 0;
412
413 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_PERF_VFE_VAR_TYPE_DERIVED_PRODUCT)
414 return -EINVAL;
415
416 ptmpobj->type_mask |= BIT(CTRL_PERF_VFE_VAR_TYPE_DERIVED_PRODUCT);
417 status = vfe_var_construct_derived(g, ppboardobj, size, pargs);
418 if (status)
419 return -EINVAL;
420
421 pvfevar = (struct vfe_var_derived_product *)*ppboardobj;
422
423 pvfevar->super.super.super.pmudatainit =
424 _vfe_var_pmudatainit_derived_product;
425
426 pvfevar->var_idx0 = ptmpvar->var_idx0;
427 pvfevar->var_idx1 = ptmpvar->var_idx1;
428
429
430 return status;
431}
432
433static u32 _vfe_var_pmudatainit_derived_sum(struct gk20a *g,
434 struct boardobj *board_obj_ptr,
435 struct nv_pmu_boardobj *ppmudata)
436{
437 u32 status = 0;
438 struct vfe_var_derived_sum *pvfe_var_derived_sum;
439 struct nv_pmu_vfe_var_derived_sum *pset;
440
441 gk20a_dbg_info("");
442
443 status = _vfe_var_pmudatainit_derived(g, board_obj_ptr, ppmudata);
444 if (status != 0)
445 return status;
446
447 pvfe_var_derived_sum = (struct vfe_var_derived_sum *)board_obj_ptr;
448 pset = (struct nv_pmu_vfe_var_derived_sum *)ppmudata;
449
450 pset->var_idx0 = pvfe_var_derived_sum->var_idx0;
451 pset->var_idx1 = pvfe_var_derived_sum->var_idx1;
452
453 return status;
454}
455
456static u32 vfe_var_construct_derived_sum(struct gk20a *g,
457 struct boardobj **ppboardobj,
458 u16 size, void *pargs)
459{
460 struct boardobj *ptmpobj = (struct boardobj *)pargs;
461 struct vfe_var_derived_sum *pvfevar;
462 struct vfe_var_derived_sum *ptmpvar =
463 (struct vfe_var_derived_sum *)pargs;
464 u32 status = 0;
465
466 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_PERF_VFE_VAR_TYPE_DERIVED_SUM)
467 return -EINVAL;
468
469 ptmpobj->type_mask |= BIT(CTRL_PERF_VFE_VAR_TYPE_DERIVED_SUM);
470 status = vfe_var_construct_derived(g, ppboardobj, size, pargs);
471 if (status)
472 return -EINVAL;
473
474 pvfevar = (struct vfe_var_derived_sum *)*ppboardobj;
475
476 pvfevar->super.super.super.pmudatainit =
477 _vfe_var_pmudatainit_derived_sum;
478
479 pvfevar->var_idx0 = ptmpvar->var_idx0;
480 pvfevar->var_idx1 = ptmpvar->var_idx1;
481
482 return status;
483}
484
485static u32 _vfe_var_pmudatainit_single(struct gk20a *g,
486 struct boardobj *board_obj_ptr,
487 struct nv_pmu_boardobj *ppmudata)
488{
489 u32 status = 0;
490 struct vfe_var_single *pvfe_var_single;
491 struct nv_pmu_vfe_var_single *pset;
492
493 gk20a_dbg_info("");
494
495 status = _vfe_var_pmudatainit_super(g, board_obj_ptr, ppmudata);
496 if (status != 0)
497 return status;
498
499 pvfe_var_single = (struct vfe_var_single *)board_obj_ptr;
500 pset = (struct nv_pmu_vfe_var_single *)
501 ppmudata;
502
503 pset->override_type = pvfe_var_single->override_type;
504 pset->override_value = pvfe_var_single->override_value;
505
506 return status;
507}
508
509static u32 _vfe_var_pmudatainit_single_frequency(struct gk20a *g,
510 struct boardobj *board_obj_ptr,
511 struct nv_pmu_boardobj *ppmudata)
512{
513 u32 status = 0;
514
515 gk20a_dbg_info("");
516
517 status = _vfe_var_pmudatainit_single(g, board_obj_ptr, ppmudata);
518
519 return status;
520}
521
522static u32 vfe_var_construct_single_frequency(struct gk20a *g,
523 struct boardobj **ppboardobj,
524 u16 size, void *pargs)
525{
526 struct boardobj *ptmpobj = (struct boardobj *)pargs;
527 struct vfe_var_single_frequency *pvfevar;
528 u32 status = 0;
529
530 gk20a_dbg_info("");
531
532 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_PERF_VFE_VAR_TYPE_SINGLE_FREQUENCY)
533 return -EINVAL;
534
535 ptmpobj->type_mask |= BIT(CTRL_PERF_VFE_VAR_TYPE_SINGLE_FREQUENCY);
536 status = vfe_var_construct_single(g, ppboardobj, size, pargs);
537 if (status)
538 return -EINVAL;
539
540 pvfevar = (struct vfe_var_single_frequency *)*ppboardobj;
541
542 pvfevar->super.super.super.pmudatainit =
543 _vfe_var_pmudatainit_single_frequency;
544
545 pvfevar->super.super.b_is_dynamic = false;
546 pvfevar->super.super.b_is_dynamic_valid = true;
547
548 gk20a_dbg_info("Done");
549 return status;
550}
551
552static u32 _vfe_var_pmudatainit_single_sensed(struct gk20a *g,
553 struct boardobj *board_obj_ptr,
554 struct nv_pmu_boardobj *ppmudata)
555{
556 u32 status = 0;
557
558 gk20a_dbg_info("");
559
560 status = _vfe_var_pmudatainit_single(g, board_obj_ptr, ppmudata);
561
562 return status;
563}
564
565static u32 _vfe_var_pmudatainit_single_sensed_fuse(struct gk20a *g,
566 struct boardobj *board_obj_ptr,
567 struct nv_pmu_boardobj *ppmudata)
568{
569 u32 status = 0;
570 struct vfe_var_single_sensed_fuse *pvfe_var_single_sensed_fuse;
571 struct nv_pmu_vfe_var_single_sensed_fuse *pset;
572
573 gk20a_dbg_info("");
574
575 status = _vfe_var_pmudatainit_single_sensed(g, board_obj_ptr, ppmudata);
576 if (status != 0)
577 return status;
578
579 pvfe_var_single_sensed_fuse =
580 (struct vfe_var_single_sensed_fuse *)board_obj_ptr;
581
582 pset = (struct nv_pmu_vfe_var_single_sensed_fuse *)
583 ppmudata;
584
585 memcpy(&pset->vfield_info, &pvfe_var_single_sensed_fuse->vfield_info,
586 sizeof(struct nv_pmu_vfe_var_single_sensed_fuse_vfield_info));
587
588 memcpy(&pset->vfield_ver_info,
589 &pvfe_var_single_sensed_fuse->vfield_ver_info,
590 sizeof(struct nv_pmu_vfe_var_single_sensed_fuse_ver_vfield_info));
591
592 memcpy(&pset->override_info,
593 &pvfe_var_single_sensed_fuse->override_info,
594 sizeof(struct nv_pmu_vfe_var_single_sensed_fuse_override_info));
595
596 return status;
597}
598
599static u32 vfe_var_construct_single_sensed(struct gk20a *g,
600 struct boardobj **ppboardobj,
601 u16 size, void *pargs)
602{
603 struct boardobj *ptmpobj = (struct boardobj *)pargs;
604 struct vfe_var_single_sensed *pvfevar;
605
606 u32 status = 0;
607
608 gk20a_dbg_info(" ");
609
610 ptmpobj->type_mask |= BIT(CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED);
611 status = vfe_var_construct_single(g, ppboardobj, size, pargs);
612 if (status)
613 return -EINVAL;
614
615 pvfevar = (struct vfe_var_single_sensed *)*ppboardobj;
616
617 pvfevar->super.super.super.pmudatainit =
618 _vfe_var_pmudatainit_single_sensed;
619
620 gk20a_dbg_info("Done");
621
622 return status;
623}
624
625static u32 vfe_var_construct_single_sensed_fuse(struct gk20a *g,
626 struct boardobj **ppboardobj,
627 u16 size, void *pargs)
628{
629 struct boardobj *ptmpobj = (struct boardobj *)pargs;
630 struct vfe_var_single_sensed_fuse *pvfevar;
631 struct vfe_var_single_sensed_fuse *ptmpvar =
632 (struct vfe_var_single_sensed_fuse *)pargs;
633 u32 status = 0;
634
635 gk20a_dbg_info("");
636
637 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED_FUSE)
638 return -EINVAL;
639
640 ptmpobj->type_mask |= BIT(CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED_FUSE);
641 status = vfe_var_construct_single_sensed(g, ppboardobj, size, pargs);
642 if (status)
643 return -EINVAL;
644
645 pvfevar = (struct vfe_var_single_sensed_fuse *)*ppboardobj;
646
647 pvfevar->super.super.super.super.pmudatainit =
648 _vfe_var_pmudatainit_single_sensed_fuse;
649
650 pvfevar->vfield_info.v_field_id = ptmpvar->vfield_info.v_field_id;
651 pvfevar->vfield_info.fuse_val_default =
652 ptmpvar->vfield_info.fuse_val_default;
653 pvfevar->vfield_info.hw_correction_scale =
654 ptmpvar->vfield_info.hw_correction_scale;
655 pvfevar->vfield_info.hw_correction_offset =
656 ptmpvar->vfield_info.hw_correction_offset;
657 pvfevar->vfield_ver_info.v_field_id_ver =
658 ptmpvar->vfield_ver_info.v_field_id_ver;
659 pvfevar->vfield_ver_info.ver_expected =
660 ptmpvar->vfield_ver_info.ver_expected;
661 pvfevar->vfield_ver_info.b_use_default_on_ver_check_fail =
662 ptmpvar->vfield_ver_info.b_use_default_on_ver_check_fail;
663 pvfevar->b_version_check_done = false;
664
665 pvfevar->super.super.super.b_is_dynamic = false;
666 pvfevar->super.super.super.b_is_dynamic_valid = true;
667
668 dev_init_get_vfield_info(g, pvfevar);
669 /*check whether fuse segment got initialized*/
670 if (pvfevar->vfield_info.fuse.segment_count == 0) {
671 nvgpu_err(g, "unable to get fuse reg info %x",
672 pvfevar->vfield_info.v_field_id);
673 status = -EINVAL;
674 goto exit;
675 }
676 if (pvfevar->vfield_ver_info.fuse.segment_count == 0) {
677 nvgpu_err(g, "unable to get fuse reg info %x",
678 pvfevar->vfield_ver_info.v_field_id_ver);
679 status = -EINVAL;
680 goto exit;
681 }
682exit:
683 if (status)
684 (*ppboardobj)->destruct(*ppboardobj);
685
686 return status;
687}
688
689static u32 _vfe_var_pmudatainit_single_sensed_temp(struct gk20a *g,
690 struct boardobj *board_obj_ptr,
691 struct nv_pmu_boardobj *ppmudata)
692{
693 u32 status = 0;
694 struct vfe_var_single_sensed_temp *pvfe_var_single_sensed_temp;
695 struct nv_pmu_vfe_var_single_sensed_temp *pset;
696
697 gk20a_dbg_info("");
698
699 status = _vfe_var_pmudatainit_single_sensed(g, board_obj_ptr, ppmudata);
700 if (status != 0)
701 return status;
702
703 pvfe_var_single_sensed_temp =
704 (struct vfe_var_single_sensed_temp *)board_obj_ptr;
705
706 pset = (struct nv_pmu_vfe_var_single_sensed_temp *)
707 ppmudata;
708 pset->therm_channel_index =
709 pvfe_var_single_sensed_temp->therm_channel_index;
710 pset->temp_hysteresis_positive =
711 pvfe_var_single_sensed_temp->temp_hysteresis_positive;
712 pset->temp_hysteresis_negative =
713 pvfe_var_single_sensed_temp->temp_hysteresis_negative;
714 pset->temp_default =
715 pvfe_var_single_sensed_temp->temp_default;
716 return status;
717}
718
719static u32 vfe_var_construct_single_sensed_temp(struct gk20a *g,
720 struct boardobj **ppboardobj,
721 u16 size, void *pargs)
722{
723 struct boardobj *ptmpobj = (struct boardobj *)pargs;
724 struct vfe_var_single_sensed_temp *pvfevar;
725 struct vfe_var_single_sensed_temp *ptmpvar =
726 (struct vfe_var_single_sensed_temp *)pargs;
727 u32 status = 0;
728
729 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED_TEMP)
730 return -EINVAL;
731
732 ptmpobj->type_mask |= BIT(CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED_TEMP);
733 status = vfe_var_construct_single_sensed(g, ppboardobj, size, pargs);
734 if (status)
735 return -EINVAL;
736
737 pvfevar = (struct vfe_var_single_sensed_temp *)*ppboardobj;
738
739 pvfevar->super.super.super.super.pmudatainit =
740 _vfe_var_pmudatainit_single_sensed_temp;
741
742 pvfevar->therm_channel_index =
743 ptmpvar->therm_channel_index;
744 pvfevar->temp_hysteresis_positive =
745 ptmpvar->temp_hysteresis_positive;
746 pvfevar->temp_hysteresis_negative =
747 ptmpvar->temp_hysteresis_negative;
748 pvfevar->temp_default =
749 ptmpvar->temp_default;
750 pvfevar->super.super.super.b_is_dynamic = false;
751 pvfevar->super.super.super.b_is_dynamic_valid = true;
752
753 return status;
754}
755
756static u32 _vfe_var_pmudatainit_single_voltage(struct gk20a *g,
757 struct boardobj *board_obj_ptr,
758 struct nv_pmu_boardobj *ppmudata)
759{
760 u32 status = 0;
761
762 gk20a_dbg_info("");
763
764 status = _vfe_var_pmudatainit_single(g, board_obj_ptr, ppmudata);
765
766 return status;
767}
768
769static u32 vfe_var_construct_single_voltage(struct gk20a *g,
770 struct boardobj **ppboardobj,
771 u16 size, void *pargs)
772{
773 struct boardobj *ptmpobj = (struct boardobj *)pargs;
774 struct vfe_var_single_voltage *pvfevar;
775 u32 status = 0;
776
777 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_PERF_VFE_VAR_TYPE_SINGLE_VOLTAGE)
778 return -EINVAL;
779
780 ptmpobj->type_mask |= BIT(CTRL_PERF_VFE_VAR_TYPE_SINGLE_VOLTAGE);
781 status = vfe_var_construct_super(g, ppboardobj, size, pargs);
782 if (status)
783 return -EINVAL;
784
785 pvfevar = (struct vfe_var_single_voltage *)*ppboardobj;
786
787 pvfevar->super.super.super.pmudatainit =
788 _vfe_var_pmudatainit_single_voltage;
789
790 pvfevar->super.super.b_is_dynamic = false;
791 pvfevar->super.super.b_is_dynamic_valid = true;
792
793 return status;
794}
795
796static struct vfe_var *construct_vfe_var(struct gk20a *g, void *pargs)
797{
798 struct boardobj *board_obj_ptr = NULL;
799 u32 status;
800
801 gk20a_dbg_info("");
802 switch (BOARDOBJ_GET_TYPE(pargs)) {
803 case CTRL_PERF_VFE_VAR_TYPE_DERIVED_PRODUCT:
804 status = vfe_var_construct_derived_product(g, &board_obj_ptr,
805 sizeof(struct vfe_var_derived_product), pargs);
806 break;
807
808 case CTRL_PERF_VFE_VAR_TYPE_DERIVED_SUM:
809 status = vfe_var_construct_derived_sum(g, &board_obj_ptr,
810 sizeof(struct vfe_var_derived_sum), pargs);
811 break;
812
813 case CTRL_PERF_VFE_VAR_TYPE_SINGLE_FREQUENCY:
814 status = vfe_var_construct_single_frequency(g, &board_obj_ptr,
815 sizeof(struct vfe_var_single_frequency), pargs);
816 break;
817
818 case CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED_FUSE:
819 status = vfe_var_construct_single_sensed_fuse(g, &board_obj_ptr,
820 sizeof(struct vfe_var_single_sensed_fuse), pargs);
821 break;
822
823 case CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED_TEMP:
824 status = vfe_var_construct_single_sensed_temp(g, &board_obj_ptr,
825 sizeof(struct vfe_var_single_sensed_temp), pargs);
826 break;
827
828 case CTRL_PERF_VFE_VAR_TYPE_SINGLE_VOLTAGE:
829 status = vfe_var_construct_single_voltage(g, &board_obj_ptr,
830 sizeof(struct vfe_var_single_voltage), pargs);
831 break;
832
833 case CTRL_PERF_VFE_VAR_TYPE_DERIVED:
834 case CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED:
835 case CTRL_PERF_VFE_VAR_TYPE_SINGLE:
836 default:
837 return NULL;
838 }
839
840 if (status)
841 return NULL;
842
843 gk20a_dbg_info("done");
844
845 return (struct vfe_var *)board_obj_ptr;
846}
847
848static u32 devinit_get_vfe_var_table(struct gk20a *g,
849 struct vfe_vars *pvfevarobjs)
850{
851 u32 status = 0;
852 u8 *vfevars_tbl_ptr = NULL;
853 struct vbios_vfe_3x_header_struct vfevars_tbl_header = { 0 };
854 struct vbios_vfe_3x_var_entry_struct var = { 0 };
855 u8 *vfevars_tbl_entry_ptr = NULL;
856 u8 *rd_offset_ptr = NULL;
857 u32 index = 0;
858 struct vfe_var *pvar;
859 u8 var_type;
860 u32 szfmt;
861 union {
862 struct boardobj board_obj;
863 struct vfe_var super;
864 struct vfe_var_derived_product derived_product;
865 struct vfe_var_derived_sum derived_sum;
866 struct vfe_var_single_sensed_fuse single_sensed_fuse;
867 struct vfe_var_single_sensed_temp single_sensed_temp;
868 } var_data;
869
870 gk20a_dbg_info("");
871
872 vfevars_tbl_ptr = (u8 *)nvgpu_bios_get_perf_table_ptrs(g,
873 g->bios.perf_token,
874 CONTINUOUS_VIRTUAL_BINNING_TABLE);
875 if (vfevars_tbl_ptr == NULL) {
876 status = -EINVAL;
877 goto done;
878 }
879
880 memcpy(&vfevars_tbl_header, vfevars_tbl_ptr,
881 VBIOS_CLOCKS_TABLE_1X_HEADER_SIZE_07);
882 if (vfevars_tbl_header.header_size !=
883 VBIOS_CLOCKS_TABLE_1X_HEADER_SIZE_07){
884 status = -EINVAL;
885 goto done;
886 }
887
888 if (vfevars_tbl_header.vfe_var_entry_size ==
889 VBIOS_VFE_3X_VAR_ENTRY_SIZE_19)
890 szfmt = VBIOS_VFE_3X_VAR_ENTRY_SIZE_19;
891 else if (vfevars_tbl_header.vfe_var_entry_size ==
892 VBIOS_VFE_3X_VAR_ENTRY_SIZE_11)
893 szfmt = VBIOS_VFE_3X_VAR_ENTRY_SIZE_11;
894 else {
895 status = -EINVAL;
896 goto done;
897 }
898
899 /* Read table entries*/
900 vfevars_tbl_entry_ptr = vfevars_tbl_ptr +
901 vfevars_tbl_header.header_size;
902
903 for (index = 0;
904 index < vfevars_tbl_header.vfe_var_entry_count;
905 index++) {
906 rd_offset_ptr = vfevars_tbl_entry_ptr +
907 (index * vfevars_tbl_header.vfe_var_entry_size);
908 memcpy(&var, rd_offset_ptr, szfmt);
909
910 var_data.super.out_range_min = var.out_range_min;
911 var_data.super.out_range_max = var.out_range_max;
912
913 var_data.super.out_range_min = var.out_range_min;
914 var_data.super.out_range_max = var.out_range_max;
915
916 switch ((u8)var.type) {
917 case VBIOS_VFE_3X_VAR_ENTRY_TYPE_DISABLED:
918 continue;
919 break;
920
921 case VBIOS_VFE_3X_VAR_ENTRY_TYPE_SINGLE_FREQUENCY:
922 var_type = CTRL_PERF_VFE_VAR_TYPE_SINGLE_FREQUENCY;
923 break;
924
925 case VBIOS_VFE_3X_VAR_ENTRY_TYPE_SINGLE_VOLTAGE:
926 var_type = CTRL_PERF_VFE_VAR_TYPE_SINGLE_VOLTAGE;
927 break;
928
929 case VBIOS_VFE_3X_VAR_ENTRY_TYPE_SINGLE_SENSED_TEMP:
930 var_type = CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED_TEMP;
931 var_data.single_sensed_temp.temp_default = 0x9600;
932 var_data.single_sensed_temp.therm_channel_index =
933 (u8)BIOS_GET_FIELD(var.param0,
934 VBIOS_VFE_3X_VAR_ENTRY_PAR0_SSTEMP_TH_CH_IDX);
935 var_data.single_sensed_temp.temp_hysteresis_positive =
936 (u8)BIOS_GET_FIELD(var.param0,
937 VBIOS_VFE_3X_VAR_ENTRY_PAR0_SSTEMP_HYS_POS) << 5;
938 var_data.single_sensed_temp.temp_hysteresis_negative =
939 (u8)BIOS_GET_FIELD(var.param0,
940 VBIOS_VFE_3X_VAR_ENTRY_PAR0_SSTEMP_HYS_NEG) << 5;
941 break;
942
943 case VBIOS_VFE_3X_VAR_ENTRY_TYPE_SINGLE_SENSED_FUSE:
944 var_type = CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED_FUSE;
945 var_data.single_sensed_fuse.vfield_info.v_field_id =
946 (u8)BIOS_GET_FIELD(var.param0,
947 VBIOS_VFE_3X_VAR_ENTRY_PAR0_SSFUSE_VFIELD_ID);
948 var_data.single_sensed_fuse.vfield_ver_info.v_field_id_ver =
949 (u8)BIOS_GET_FIELD(var.param0,
950 VBIOS_VFE_3X_VAR_ENTRY_PAR0_SSFUSE_VFIELD_ID_VER);
951 var_data.single_sensed_fuse.vfield_ver_info.ver_expected =
952 (u8)BIOS_GET_FIELD(var.param0,
953 VBIOS_VFE_3X_VAR_ENTRY_PAR0_SSFUSE_EXPECTED_VER);
954 var_data.single_sensed_fuse.vfield_ver_info.b_use_default_on_ver_check_fail =
955 (BIOS_GET_FIELD(var.param0,
956 VBIOS_VFE_3X_VAR_ENTRY_PAR0_SSFUSE_USE_DEFAULT_ON_VER_CHECK_FAIL) &&
957 VBIOS_VFE_3X_VAR_ENTRY_PAR0_SSFUSE_USE_DEFAULT_ON_VER_CHECK_FAIL_YES);
958 var_data.single_sensed_fuse.vfield_info.fuse_val_default =
959 var.param1;
960 if (szfmt >= VBIOS_VFE_3X_VAR_ENTRY_SIZE_19) {
961 var_data.single_sensed_fuse.vfield_info.hw_correction_scale =
962 (int)var.param2;
963 var_data.single_sensed_fuse.vfield_info.hw_correction_offset =
964 var.param3;
965 } else {
966 var_data.single_sensed_fuse.vfield_info.hw_correction_scale =
967 1 << 12;
968 var_data.single_sensed_fuse.vfield_info.hw_correction_offset =
969 0;
970 if ((var_data.single_sensed_fuse.vfield_info.v_field_id ==
971 VFIELD_ID_STRAP_IDDQ) ||
972 (var_data.single_sensed_fuse.vfield_info.v_field_id ==
973 VFIELD_ID_STRAP_IDDQ_1)) {
974 var_data.single_sensed_fuse.vfield_info.hw_correction_scale =
975 50 << 12;
976 }
977 }
978 break;
979
980 case VBIOS_VFE_3X_VAR_ENTRY_TYPE_DERIVED_PRODUCT:
981 var_type = CTRL_PERF_VFE_VAR_TYPE_DERIVED_PRODUCT;
982 var_data.derived_product.var_idx0 =
983 (u8)BIOS_GET_FIELD(var.param0,
984 VBIOS_VFE_3X_VAR_ENTRY_PAR0_DPROD_VFE_VAR_IDX_0);
985 var_data.derived_product.var_idx1 =
986 (u8)BIOS_GET_FIELD(var.param0,
987 VBIOS_VFE_3X_VAR_ENTRY_PAR0_DPROD_VFE_VAR_IDX_1);
988 break;
989
990 case VBIOS_VFE_3X_VAR_ENTRY_TYPE_DERIVED_SUM:
991 var_type = CTRL_PERF_VFE_VAR_TYPE_DERIVED_SUM;
992 var_data.derived_sum.var_idx0 =
993 (u8)BIOS_GET_FIELD(var.param0,
994 VBIOS_VFE_3X_VAR_ENTRY_PAR0_DSUM_VFE_VAR_IDX_0);
995 var_data.derived_sum.var_idx1 =
996 (u8)BIOS_GET_FIELD(var.param0,
997 VBIOS_VFE_3X_VAR_ENTRY_PAR0_DSUM_VFE_VAR_IDX_1);
998 break;
999 default:
1000 status = -EINVAL;
1001 goto done;
1002 }
1003 var_data.board_obj.type = var_type;
1004 var_data.board_obj.type_mask = 0;
1005
1006 pvar = construct_vfe_var(g, &var_data);
1007 if (pvar == NULL) {
1008 nvgpu_err(g,
1009 "error constructing vfe_var boardobj %d",
1010 index);
1011 status = -EINVAL;
1012 goto done;
1013 }
1014
1015 status = boardobjgrp_objinsert(&pvfevarobjs->super.super,
1016 (struct boardobj *)pvar, index);
1017 if (status) {
1018 nvgpu_err(g, "error adding vfe_var boardobj %d", index);
1019 status = -EINVAL;
1020 goto done;
1021 }
1022 }
1023 pvfevarobjs->polling_periodms = vfevars_tbl_header.polling_periodms;
1024done:
1025 gk20a_dbg_info("done status %x", status);
1026 return status;
1027}
1028
1029static u32 vfe_var_construct_single(struct gk20a *g,
1030 struct boardobj **ppboardobj,
1031 u16 size, void *pargs)
1032{
1033 struct boardobj *ptmpobj = (struct boardobj *)pargs;
1034 struct vfe_var_single *pvfevar;
1035 u32 status = 0;
1036
1037 gk20a_dbg_info("");
1038
1039 ptmpobj->type_mask |= BIT(CTRL_PERF_VFE_VAR_TYPE_SINGLE);
1040 status = vfe_var_construct_super(g, ppboardobj, size, pargs);
1041 if (status)
1042 return -EINVAL;
1043
1044 pvfevar = (struct vfe_var_single *)*ppboardobj;
1045
1046 pvfevar->super.super.pmudatainit =
1047 _vfe_var_pmudatainit_single;
1048
1049 pvfevar->override_type = CTRL_PERF_VFE_VAR_SINGLE_OVERRIDE_TYPE_NONE;
1050 pvfevar->override_value = 0;
1051
1052 gk20a_dbg_info("Done");
1053 return status;
1054}