aboutsummaryrefslogtreecommitdiffstats
path: root/include/clk/clk_prog.c
diff options
context:
space:
mode:
Diffstat (limited to 'include/clk/clk_prog.c')
-rw-r--r--include/clk/clk_prog.c1152
1 files changed, 0 insertions, 1152 deletions
diff --git a/include/clk/clk_prog.c b/include/clk/clk_prog.c
deleted file mode 100644
index 9d44d6d..0000000
--- a/include/clk/clk_prog.c
+++ /dev/null
@@ -1,1152 +0,0 @@
1/*
2 * Copyright (c) 2016-2020, 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#include <nvgpu/kmem.h>
25#include <nvgpu/gk20a.h>
26
27#include "clk.h"
28#include "clk_prog.h"
29#include "clk_vf_point.h"
30#include "boardobj/boardobjgrp.h"
31#include "boardobj/boardobjgrp_e32.h"
32#include "gp106/bios_gp106.h"
33#include "ctrl/ctrlclk.h"
34#include "ctrl/ctrlvolt.h"
35
36static struct clk_prog *construct_clk_prog(struct gk20a *g, void *pargs);
37static int devinit_get_clk_prog_table(struct gk20a *g,
38 struct clk_progs *pprogobjs);
39static vf_flatten vfflatten_prog_1x_master;
40static vf_lookup vflookup_prog_1x_master;
41static get_fpoints getfpoints_prog_1x_master;
42static get_slaveclk getslaveclk_prog_1x_master;
43
44static int _clk_progs_pmudatainit(struct gk20a *g,
45 struct boardobjgrp *pboardobjgrp,
46 struct nv_pmu_boardobjgrp_super *pboardobjgrppmu)
47{
48 struct nv_pmu_clk_clk_prog_boardobjgrp_set_header *pset =
49 (struct nv_pmu_clk_clk_prog_boardobjgrp_set_header *)
50 pboardobjgrppmu;
51 struct clk_progs *pprogs = (struct clk_progs *)pboardobjgrp;
52 u32 status = 0;
53
54 status = boardobjgrp_pmudatainit_e32(g, pboardobjgrp, pboardobjgrppmu);
55 if (status) {
56 nvgpu_err(g, "error updating pmu boardobjgrp for clk prog 0x%x",
57 status);
58 goto done;
59 }
60 pset->slave_entry_count = pprogs->slave_entry_count;
61 pset->vf_entry_count = pprogs->vf_entry_count;
62
63done:
64 return status;
65}
66
67static int _clk_progs_pmudata_instget(struct gk20a *g,
68 struct nv_pmu_boardobjgrp *pmuboardobjgrp,
69 struct nv_pmu_boardobj **ppboardobjpmudata,
70 u8 idx)
71{
72 struct nv_pmu_clk_clk_prog_boardobj_grp_set *pgrp_set =
73 (struct nv_pmu_clk_clk_prog_boardobj_grp_set *)pmuboardobjgrp;
74
75 nvgpu_log_info(g, " ");
76
77 /*check whether pmuboardobjgrp has a valid boardobj in index*/
78 if (((u32)BIT(idx) &
79 pgrp_set->hdr.data.super.obj_mask.super.data[0]) == 0) {
80 return -EINVAL;
81 }
82
83 *ppboardobjpmudata = (struct nv_pmu_boardobj *)
84 &pgrp_set->objects[idx].data.board_obj;
85 nvgpu_log_info(g, " Done");
86 return 0;
87}
88
89int clk_prog_sw_setup(struct gk20a *g)
90{
91 int status;
92 struct boardobjgrp *pboardobjgrp = NULL;
93 struct clk_progs *pclkprogobjs;
94
95 nvgpu_log_info(g, " ");
96
97 status = boardobjgrpconstruct_e255(g, &g->clk_pmu.clk_progobjs.super);
98 if (status) {
99 nvgpu_err(g,
100 "error creating boardobjgrp for clk prog, status - 0x%x",
101 status);
102 goto done;
103 }
104
105 pboardobjgrp = &g->clk_pmu.clk_progobjs.super.super;
106 pclkprogobjs = &(g->clk_pmu.clk_progobjs);
107
108 BOARDOBJGRP_PMU_CONSTRUCT(pboardobjgrp, CLK, CLK_PROG);
109
110 status = BOARDOBJGRP_PMU_CMD_GRP_SET_CONSTRUCT(g, pboardobjgrp,
111 clk, CLK, clk_prog, CLK_PROG);
112 if (status) {
113 nvgpu_err(g,
114 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
115 status);
116 goto done;
117 }
118
119 pboardobjgrp->pmudatainit = _clk_progs_pmudatainit;
120 pboardobjgrp->pmudatainstget = _clk_progs_pmudata_instget;
121
122 status = devinit_get_clk_prog_table(g, pclkprogobjs);
123 if (status) {
124 goto done;
125 }
126
127 status = clk_domain_clk_prog_link(g, &g->clk_pmu);
128 if (status) {
129 nvgpu_err(g, "error constructing VF point board objects");
130 goto done;
131 }
132
133
134done:
135 nvgpu_log_info(g, " done status %x", status);
136 return status;
137}
138
139int clk_prog_pmu_setup(struct gk20a *g)
140{
141 int status;
142 struct boardobjgrp *pboardobjgrp = NULL;
143
144 nvgpu_log_info(g, " ");
145
146 pboardobjgrp = &g->clk_pmu.clk_progobjs.super.super;
147
148 if (!pboardobjgrp->bconstructed) {
149 return -EINVAL;
150 }
151
152 status = pboardobjgrp->pmuinithandle(g, pboardobjgrp);
153
154 nvgpu_log_info(g, "Done");
155 return status;
156}
157
158static int devinit_get_clk_prog_table(struct gk20a *g,
159 struct clk_progs *pclkprogobjs)
160{
161 int status = 0;
162 u8 *clkprogs_tbl_ptr = NULL;
163 struct vbios_clock_programming_table_1x_header header = { 0 };
164 struct vbios_clock_programming_table_1x_entry prog = { 0 };
165 struct vbios_clock_programming_table_1x_slave_entry slaveprog = { 0 };
166 struct vbios_clock_programming_table_1x_vf_entry vfprog = { 0 };
167 u8 *entry = NULL;
168 u8 *slaveentry = NULL;
169 u8 *vfentry = NULL;
170 u32 i, j = 0;
171 struct clk_prog *pprog;
172 u8 prog_type;
173 u32 szfmt = VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_SIZE_0D;
174 u32 hszfmt = VBIOS_CLOCK_PROGRAMMING_TABLE_1X_HEADER_SIZE_08;
175 u32 slaveszfmt = VBIOS_CLOCK_PROGRAMMING_TABLE_1X_SLAVE_ENTRY_SIZE_03;
176 u32 vfszfmt = VBIOS_CLOCK_PROGRAMMING_TABLE_1X_VF_ENTRY_SIZE_02;
177 struct ctrl_clk_clk_prog_1x_master_vf_entry
178 vfentries[CTRL_CLK_CLK_PROG_1X_MASTER_VF_ENTRY_MAX_ENTRIES];
179 struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry
180 ratioslaveentries[CTRL_CLK_PROG_1X_MASTER_MAX_SLAVE_ENTRIES];
181 struct ctrl_clk_clk_prog_1x_master_table_slave_entry
182 tableslaveentries[CTRL_CLK_PROG_1X_MASTER_MAX_SLAVE_ENTRIES];
183 union {
184 struct boardobj board_obj;
185 struct clk_prog clkprog;
186 struct clk_prog_1x v1x;
187 struct clk_prog_1x_master v1x_master;
188 struct clk_prog_1x_master_ratio v1x_master_ratio;
189 struct clk_prog_1x_master_table v1x_master_table;
190 } prog_data;
191
192 nvgpu_log_info(g, " ");
193
194 clkprogs_tbl_ptr = (u8 *)nvgpu_bios_get_perf_table_ptrs(g,
195 g->bios.clock_token, CLOCK_PROGRAMMING_TABLE);
196 if (clkprogs_tbl_ptr == NULL) {
197 status = -EINVAL;
198 goto done;
199 }
200
201 memcpy(&header, clkprogs_tbl_ptr, hszfmt);
202 if (header.header_size < hszfmt) {
203 status = -EINVAL;
204 goto done;
205 }
206 hszfmt = header.header_size;
207
208 if (header.entry_size <= VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_SIZE_05) {
209 szfmt = header.entry_size;
210 } else if (header.entry_size <= VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_SIZE_0D) {
211 szfmt = header.entry_size;
212 } else {
213 status = -EINVAL;
214 goto done;
215 }
216
217 if (header.vf_entry_size < vfszfmt) {
218 status = -EINVAL;
219 goto done;
220 }
221 vfszfmt = header.vf_entry_size;
222 if (header.slave_entry_size < slaveszfmt) {
223 status = -EINVAL;
224 goto done;
225 }
226 slaveszfmt = header.slave_entry_size;
227 if (header.vf_entry_count > CTRL_CLK_CLK_DELTA_MAX_VOLT_RAILS) {
228 status = -EINVAL;
229 goto done;
230 }
231
232 pclkprogobjs->slave_entry_count = header.slave_entry_count;
233 pclkprogobjs->vf_entry_count = header.vf_entry_count;
234
235 for (i = 0; i < header.entry_count; i++) {
236 memset(&prog_data, 0x0, (u32)sizeof(prog_data));
237
238 /* Read table entries*/
239 entry = clkprogs_tbl_ptr + hszfmt +
240 (i * (szfmt + (header.slave_entry_count * slaveszfmt) +
241 (header.vf_entry_count * vfszfmt)));
242
243 memcpy(&prog, entry, szfmt);
244 memset(vfentries, 0xFF,
245 sizeof(struct ctrl_clk_clk_prog_1x_master_vf_entry) *
246 CTRL_CLK_CLK_PROG_1X_MASTER_VF_ENTRY_MAX_ENTRIES);
247 memset(ratioslaveentries, 0xFF,
248 sizeof(struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry) *
249 CTRL_CLK_PROG_1X_MASTER_MAX_SLAVE_ENTRIES);
250 memset(tableslaveentries, 0xFF,
251 sizeof(struct ctrl_clk_clk_prog_1x_master_table_slave_entry) *
252 CTRL_CLK_PROG_1X_MASTER_MAX_SLAVE_ENTRIES);
253 prog_type = (u8)BIOS_GET_FIELD(prog.flags0,
254 NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_SOURCE);
255
256 switch (prog_type) {
257 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_SOURCE_PLL:
258 prog_data.v1x.source = CTRL_CLK_PROG_1X_SOURCE_PLL;
259 prog_data.v1x.source_data.pll.pll_idx =
260 (u8)BIOS_GET_FIELD(prog.param0,
261 NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_PARAM0_PLL_PLL_INDEX);
262 prog_data.v1x.source_data.pll.freq_step_size_mhz =
263 (u8)BIOS_GET_FIELD(prog.param1,
264 NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_PARAM1_PLL_FREQ_STEP_SIZE);
265 break;
266
267 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_SOURCE_ONE_SOURCE:
268 prog_data.v1x.source = CTRL_CLK_PROG_1X_SOURCE_ONE_SOURCE;
269 break;
270
271 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_SOURCE_FLL:
272 prog_data.v1x.source = CTRL_CLK_PROG_1X_SOURCE_FLL;
273 break;
274
275 default:
276 nvgpu_err(g, "invalid source %d", prog_type);
277 status = -EINVAL;
278 goto done;
279 }
280
281 prog_data.v1x.freq_max_mhz = (u16)prog.freq_max_mhz;
282
283 prog_type = (u8)BIOS_GET_FIELD(prog.flags0,
284 NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE);
285
286 vfentry = entry + szfmt +
287 header.slave_entry_count * slaveszfmt;
288 slaveentry = entry + szfmt;
289 switch (prog_type) {
290 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE_MASTER_RATIO:
291 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE_MASTER_TABLE:
292 prog_data.v1x_master.b_o_c_o_v_enabled = false;
293 for (j = 0; j < header.vf_entry_count; j++) {
294 memcpy(&vfprog, vfentry, vfszfmt);
295
296 vfentries[j].vfe_idx = (u8)vfprog.vfe_idx;
297 if (CTRL_CLK_PROG_1X_SOURCE_FLL ==
298 prog_data.v1x.source) {
299 vfentries[j].gain_vfe_idx = (u8)BIOS_GET_FIELD(
300 vfprog.param0,
301 NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_VF_ENTRY_PARAM0_FLL_GAIN_VFE_IDX);
302 } else {
303 vfentries[j].gain_vfe_idx = CTRL_BOARDOBJ_IDX_INVALID;
304 }
305 vfentry += vfszfmt;
306 }
307
308 prog_data.v1x_master.p_vf_entries = vfentries;
309
310 for (j = 0; j < header.slave_entry_count; j++) {
311 memcpy(&slaveprog, slaveentry, slaveszfmt);
312
313 switch (prog_type) {
314 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE_MASTER_RATIO:
315 ratioslaveentries[j].clk_dom_idx =
316 (u8)slaveprog.clk_dom_idx;
317 ratioslaveentries[j].ratio = (u8)
318 BIOS_GET_FIELD(slaveprog.param0,
319 NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_SLAVE_ENTRY_PARAM0_MASTER_RATIO_RATIO);
320 break;
321
322 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE_MASTER_TABLE:
323 tableslaveentries[j].clk_dom_idx =
324 (u8)slaveprog.clk_dom_idx;
325 tableslaveentries[j].freq_mhz =
326 (u16)BIOS_GET_FIELD(slaveprog.param0,
327 NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_SLAVE_ENTRY_PARAM0_MASTER_TABLE_FREQ);
328 break;
329 }
330 slaveentry += slaveszfmt;
331 }
332
333 switch (prog_type) {
334 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE_MASTER_RATIO:
335 prog_data.board_obj.type = CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_RATIO;
336 prog_data.v1x_master_ratio.p_slave_entries =
337 ratioslaveentries;
338 break;
339
340 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE_MASTER_TABLE:
341 prog_data.board_obj.type = CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_TABLE;
342
343 prog_data.v1x_master_table.p_slave_entries =
344 tableslaveentries;
345 break;
346
347 }
348 break;
349
350 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE_SLAVE:
351 prog_data.board_obj.type = CTRL_CLK_CLK_PROG_TYPE_1X;
352 break;
353
354
355 default:
356 nvgpu_err(g, "source issue %d", prog_type);
357 status = -EINVAL;
358 goto done;
359 }
360
361 pprog = construct_clk_prog(g, (void *)&prog_data);
362 if (pprog == NULL) {
363 nvgpu_err(g,
364 "error constructing clk_prog boardobj %d", i);
365 status = -EINVAL;
366 goto done;
367 }
368
369 status = boardobjgrp_objinsert(&pclkprogobjs->super.super,
370 (struct boardobj *)pprog, i);
371 if (status) {
372 nvgpu_err(g, "error adding clk_prog boardobj %d", i);
373 status = -EINVAL;
374 goto done;
375 }
376 }
377done:
378 nvgpu_log_info(g, " done status %x", status);
379 return status;
380}
381
382static int _clk_prog_pmudatainit_super(struct gk20a *g,
383 struct boardobj *board_obj_ptr,
384 struct nv_pmu_boardobj *ppmudata)
385{
386 int status = 0;
387
388 nvgpu_log_info(g, " ");
389
390 status = boardobj_pmudatainit_super(g, board_obj_ptr, ppmudata);
391 return status;
392}
393
394static int _clk_prog_pmudatainit_1x(struct gk20a *g,
395 struct boardobj *board_obj_ptr,
396 struct nv_pmu_boardobj *ppmudata)
397{
398 int status = 0;
399 struct clk_prog_1x *pclk_prog_1x;
400 struct nv_pmu_clk_clk_prog_1x_boardobj_set *pset;
401
402 nvgpu_log_info(g, " ");
403
404 status = _clk_prog_pmudatainit_super(g, board_obj_ptr, ppmudata);
405 if (status != 0) {
406 return status;
407 }
408
409 pclk_prog_1x = (struct clk_prog_1x *)board_obj_ptr;
410
411 pset = (struct nv_pmu_clk_clk_prog_1x_boardobj_set *)
412 ppmudata;
413
414 pset->source = pclk_prog_1x->source;
415 pset->freq_max_mhz = pclk_prog_1x->freq_max_mhz;
416 pset->source_data = pclk_prog_1x->source_data;
417
418 return status;
419}
420
421static int _clk_prog_pmudatainit_1x_master(struct gk20a *g,
422 struct boardobj *board_obj_ptr,
423 struct nv_pmu_boardobj *ppmudata)
424{
425 int status = 0;
426 struct clk_prog_1x_master *pclk_prog_1x_master;
427 struct nv_pmu_clk_clk_prog_1x_master_boardobj_set *pset;
428 u32 vfsize = sizeof(struct ctrl_clk_clk_prog_1x_master_vf_entry) *
429 g->clk_pmu.clk_progobjs.vf_entry_count;
430
431 nvgpu_log_info(g, " ");
432
433 status = _clk_prog_pmudatainit_1x(g, board_obj_ptr, ppmudata);
434
435 pclk_prog_1x_master =
436 (struct clk_prog_1x_master *)board_obj_ptr;
437
438 pset = (struct nv_pmu_clk_clk_prog_1x_master_boardobj_set *)
439 ppmudata;
440
441 memcpy(pset->vf_entries, pclk_prog_1x_master->p_vf_entries, vfsize);
442
443 pset->b_o_c_o_v_enabled = pclk_prog_1x_master->b_o_c_o_v_enabled;
444 pset->source_data = pclk_prog_1x_master->source_data;
445
446 memcpy(&pset->deltas, &pclk_prog_1x_master->deltas,
447 (u32) sizeof(struct ctrl_clk_clk_delta));
448
449 return status;
450}
451
452static int _clk_prog_pmudatainit_1x_master_ratio(struct gk20a *g,
453 struct boardobj *board_obj_ptr,
454 struct nv_pmu_boardobj *ppmudata)
455{
456 int status = 0;
457 struct clk_prog_1x_master_ratio *pclk_prog_1x_master_ratio;
458 struct nv_pmu_clk_clk_prog_1x_master_ratio_boardobj_set *pset;
459 u32 slavesize = sizeof(struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry) *
460 g->clk_pmu.clk_progobjs.slave_entry_count;
461
462 nvgpu_log_info(g, " ");
463
464 status = _clk_prog_pmudatainit_1x_master(g, board_obj_ptr, ppmudata);
465 if (status != 0) {
466 return status;
467 }
468
469 pclk_prog_1x_master_ratio =
470 (struct clk_prog_1x_master_ratio *)board_obj_ptr;
471
472 pset = (struct nv_pmu_clk_clk_prog_1x_master_ratio_boardobj_set *)
473 ppmudata;
474
475 memcpy(pset->slave_entries,
476 pclk_prog_1x_master_ratio->p_slave_entries, slavesize);
477
478 return status;
479}
480
481static int _clk_prog_pmudatainit_1x_master_table(struct gk20a *g,
482 struct boardobj *board_obj_ptr,
483 struct nv_pmu_boardobj *ppmudata)
484{
485 int status = 0;
486 struct clk_prog_1x_master_table *pclk_prog_1x_master_table;
487 struct nv_pmu_clk_clk_prog_1x_master_table_boardobj_set *pset;
488 u32 slavesize = sizeof(struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry) *
489 g->clk_pmu.clk_progobjs.slave_entry_count;
490
491 nvgpu_log_info(g, " ");
492
493 status = _clk_prog_pmudatainit_1x_master(g, board_obj_ptr, ppmudata);
494 if (status != 0) {
495 return status;
496 }
497
498 pclk_prog_1x_master_table =
499 (struct clk_prog_1x_master_table *)board_obj_ptr;
500
501 pset = (struct nv_pmu_clk_clk_prog_1x_master_table_boardobj_set *)
502 ppmudata;
503 memcpy(pset->slave_entries,
504 pclk_prog_1x_master_table->p_slave_entries, slavesize);
505
506 return status;
507}
508
509static u32 _clk_prog_1x_master_rail_construct_vf_point(struct gk20a *g,
510 struct clk_pmupstate *pclk,
511 struct clk_prog_1x_master *p1xmaster,
512 struct ctrl_clk_clk_prog_1x_master_vf_entry *p_vf_rail,
513 struct clk_vf_point *p_vf_point_tmp,
514 u8 *p_vf_point_idx)
515{
516 struct clk_vf_point *p_vf_point;
517 u32 status;
518
519 nvgpu_log_info(g, " ");
520
521 p_vf_point = construct_clk_vf_point(g, (void *)p_vf_point_tmp);
522 if (p_vf_point == NULL) {
523 status = -ENOMEM;
524 goto done;
525 }
526 status = pclk->clk_vf_pointobjs.super.super.objinsert(
527 &pclk->clk_vf_pointobjs.super.super,
528 &p_vf_point->super,
529 *p_vf_point_idx);
530 if (status) {
531 goto done;
532 }
533
534 p_vf_rail->vf_point_idx_last = (*p_vf_point_idx)++;
535
536done:
537 nvgpu_log_info(g, "done status %x", status);
538 return status;
539}
540
541static int clk_prog_construct_super(struct gk20a *g,
542 struct boardobj **ppboardobj,
543 u16 size, void *pargs)
544{
545 struct clk_prog *pclkprog;
546 int status = 0;
547
548 status = boardobj_construct_super(g, ppboardobj,
549 size, pargs);
550 if (status) {
551 return -EINVAL;
552 }
553
554 pclkprog = (struct clk_prog *)*ppboardobj;
555
556 pclkprog->super.pmudatainit =
557 _clk_prog_pmudatainit_super;
558 return status;
559}
560
561
562static int clk_prog_construct_1x(struct gk20a *g,
563 struct boardobj **ppboardobj,
564 u16 size, void *pargs)
565{
566 struct boardobj *ptmpobj = (struct boardobj *)pargs;
567 struct clk_prog_1x *pclkprog;
568 struct clk_prog_1x *ptmpprog =
569 (struct clk_prog_1x *)pargs;
570 int status = 0;
571
572 nvgpu_log_info(g, " ");
573 ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_PROG_TYPE_1X);
574 status = clk_prog_construct_super(g, ppboardobj, size, pargs);
575 if (status) {
576 return -EINVAL;
577 }
578
579 pclkprog = (struct clk_prog_1x *)*ppboardobj;
580
581 pclkprog->super.super.pmudatainit =
582 _clk_prog_pmudatainit_1x;
583
584 pclkprog->source = ptmpprog->source;
585 pclkprog->freq_max_mhz = ptmpprog->freq_max_mhz;
586 pclkprog->source_data = ptmpprog->source_data;
587
588 return status;
589}
590
591static int clk_prog_construct_1x_master(struct gk20a *g,
592 struct boardobj **ppboardobj,
593 u16 size, void *pargs)
594{
595 struct boardobj *ptmpobj = (struct boardobj *)pargs;
596 struct clk_prog_1x_master *pclkprog;
597 struct clk_prog_1x_master *ptmpprog =
598 (struct clk_prog_1x_master *)pargs;
599 int status = 0;
600 u32 vfsize = sizeof(struct ctrl_clk_clk_prog_1x_master_vf_entry) *
601 g->clk_pmu.clk_progobjs.vf_entry_count;
602 u8 railidx;
603
604 nvgpu_log_info(g, " type - %x", BOARDOBJ_GET_TYPE(pargs));
605
606 ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_PROG_TYPE_1X_MASTER);
607 status = clk_prog_construct_1x(g, ppboardobj, size, pargs);
608 if (status) {
609 return -EINVAL;
610 }
611
612 pclkprog = (struct clk_prog_1x_master *)*ppboardobj;
613
614 pclkprog->super.super.super.pmudatainit =
615 _clk_prog_pmudatainit_1x_master;
616
617 pclkprog->vfflatten =
618 vfflatten_prog_1x_master;
619
620 pclkprog->vflookup =
621 vflookup_prog_1x_master;
622
623 pclkprog->getfpoints =
624 getfpoints_prog_1x_master;
625
626 pclkprog->getslaveclk =
627 getslaveclk_prog_1x_master;
628
629 pclkprog->p_vf_entries = (struct ctrl_clk_clk_prog_1x_master_vf_entry *)
630 nvgpu_kzalloc(g, vfsize);
631 if (!pclkprog->p_vf_entries)
632 return -ENOMEM;
633
634 memcpy(pclkprog->p_vf_entries, ptmpprog->p_vf_entries, vfsize);
635
636 pclkprog->b_o_c_o_v_enabled = ptmpprog->b_o_c_o_v_enabled;
637
638 for (railidx = 0;
639 railidx < g->clk_pmu.clk_progobjs.vf_entry_count;
640 railidx++) {
641 pclkprog->p_vf_entries[railidx].vf_point_idx_first =
642 CTRL_CLK_CLK_VF_POINT_IDX_INVALID;
643 pclkprog->p_vf_entries[railidx].vf_point_idx_last =
644 CTRL_CLK_CLK_VF_POINT_IDX_INVALID;
645 }
646
647 return status;
648}
649
650static int clk_prog_construct_1x_master_ratio(struct gk20a *g,
651 struct boardobj **ppboardobj,
652 u16 size, void *pargs)
653{
654 struct boardobj *ptmpobj = (struct boardobj *)pargs;
655 struct clk_prog_1x_master_ratio *pclkprog;
656 struct clk_prog_1x_master_ratio *ptmpprog =
657 (struct clk_prog_1x_master_ratio *)pargs;
658 int status = 0;
659 u32 slavesize = sizeof(struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry) *
660 g->clk_pmu.clk_progobjs.slave_entry_count;
661
662 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_RATIO) {
663 return -EINVAL;
664 }
665
666 ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_RATIO);
667 status = clk_prog_construct_1x_master(g, ppboardobj, size, pargs);
668 if (status) {
669 return -EINVAL;
670 }
671
672 pclkprog = (struct clk_prog_1x_master_ratio *)*ppboardobj;
673
674 pclkprog->super.super.super.super.pmudatainit =
675 _clk_prog_pmudatainit_1x_master_ratio;
676
677 pclkprog->p_slave_entries =
678 (struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry *)
679 nvgpu_kzalloc(g, slavesize);
680 if (!pclkprog->p_slave_entries) {
681 return -ENOMEM;
682 }
683
684 memset(pclkprog->p_slave_entries, CTRL_CLK_CLK_DOMAIN_INDEX_INVALID,
685 slavesize);
686
687 memcpy(pclkprog->p_slave_entries, ptmpprog->p_slave_entries, slavesize);
688
689 return status;
690}
691
692static int clk_prog_construct_1x_master_table(struct gk20a *g,
693 struct boardobj **ppboardobj,
694 u16 size, void *pargs)
695{
696 struct boardobj *ptmpobj = (struct boardobj *)pargs;
697 struct clk_prog_1x_master_table *pclkprog;
698 struct clk_prog_1x_master_table *ptmpprog =
699 (struct clk_prog_1x_master_table *)pargs;
700 int status = 0;
701 u32 slavesize = sizeof(struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry) *
702 g->clk_pmu.clk_progobjs.slave_entry_count;
703
704 nvgpu_log_info(g, "type - %x", BOARDOBJ_GET_TYPE(pargs));
705
706 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_TABLE) {
707 return -EINVAL;
708 }
709
710 ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_TABLE);
711 status = clk_prog_construct_1x_master(g, ppboardobj, size, pargs);
712 if (status) {
713 return -EINVAL;
714 }
715
716 pclkprog = (struct clk_prog_1x_master_table *)*ppboardobj;
717
718 pclkprog->super.super.super.super.pmudatainit =
719 _clk_prog_pmudatainit_1x_master_table;
720
721 pclkprog->p_slave_entries =
722 (struct ctrl_clk_clk_prog_1x_master_table_slave_entry *)
723 nvgpu_kzalloc(g, slavesize);
724
725 if (!pclkprog->p_slave_entries) {
726 status = -ENOMEM;
727 goto exit;
728 }
729
730 memset(pclkprog->p_slave_entries, CTRL_CLK_CLK_DOMAIN_INDEX_INVALID,
731 slavesize);
732
733 memcpy(pclkprog->p_slave_entries, ptmpprog->p_slave_entries, slavesize);
734
735exit:
736 if (status) {
737 (*ppboardobj)->destruct(*ppboardobj);
738 }
739
740 return status;
741}
742
743static struct clk_prog *construct_clk_prog(struct gk20a *g, void *pargs)
744{
745 struct boardobj *board_obj_ptr = NULL;
746 int status;
747
748 nvgpu_log_info(g, " type - %x", BOARDOBJ_GET_TYPE(pargs));
749 switch (BOARDOBJ_GET_TYPE(pargs)) {
750 case CTRL_CLK_CLK_PROG_TYPE_1X:
751 status = clk_prog_construct_1x(g, &board_obj_ptr,
752 sizeof(struct clk_prog_1x), pargs);
753 break;
754
755 case CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_TABLE:
756 status = clk_prog_construct_1x_master_table(g, &board_obj_ptr,
757 sizeof(struct clk_prog_1x_master_table), pargs);
758 break;
759
760 case CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_RATIO:
761 status = clk_prog_construct_1x_master_ratio(g, &board_obj_ptr,
762 sizeof(struct clk_prog_1x_master_ratio), pargs);
763 break;
764
765 default:
766 return NULL;
767 }
768
769 if (status) {
770 if (board_obj_ptr) {
771 board_obj_ptr->destruct(board_obj_ptr);
772 }
773 return NULL;
774 }
775
776 nvgpu_log_info(g, " Done");
777
778 return (struct clk_prog *)board_obj_ptr;
779}
780
781static u32 vfflatten_prog_1x_master(struct gk20a *g,
782 struct clk_pmupstate *pclk,
783 struct clk_prog_1x_master *p1xmaster,
784 u8 clk_domain_idx, u16 *pfreqmaxlastmhz)
785{
786 struct ctrl_clk_clk_prog_1x_master_vf_entry *p_vf_rail;
787 union {
788 struct boardobj board_obj;
789 struct clk_vf_point vf_point;
790 struct clk_vf_point_freq freq;
791 struct clk_vf_point_volt volt;
792 } vf_point_data;
793 u32 status = 0;
794 u8 step_count;
795 u8 freq_step_size_mhz = 0;
796 u8 vf_point_idx;
797 u8 vf_rail_idx;
798
799 nvgpu_log_info(g, " ");
800 memset(&vf_point_data, 0x0, sizeof(vf_point_data));
801
802 vf_point_idx = BOARDOBJGRP_NEXT_EMPTY_IDX(
803 &pclk->clk_vf_pointobjs.super.super);
804
805 for (vf_rail_idx = 0;
806 vf_rail_idx < pclk->clk_progobjs.vf_entry_count;
807 vf_rail_idx++) {
808 u32 voltage_min_uv;
809 u32 voltage_step_size_uv;
810 u8 i;
811
812 p_vf_rail = &p1xmaster->p_vf_entries[vf_rail_idx];
813 if (p_vf_rail->vfe_idx == CTRL_BOARDOBJ_IDX_INVALID) {
814 continue;
815 }
816
817 p_vf_rail->vf_point_idx_first = vf_point_idx;
818
819 vf_point_data.vf_point.vfe_equ_idx = p_vf_rail->vfe_idx;
820 vf_point_data.vf_point.volt_rail_idx = vf_rail_idx;
821
822 step_count = 0;
823
824 switch (p1xmaster->super.source) {
825 case CTRL_CLK_PROG_1X_SOURCE_PLL:
826 freq_step_size_mhz =
827 p1xmaster->super.source_data.pll.freq_step_size_mhz;
828 step_count = (freq_step_size_mhz == 0) ? 0 :
829 (p1xmaster->super.freq_max_mhz - *pfreqmaxlastmhz - 1) /
830 freq_step_size_mhz;
831 /* Intentional fall-through.*/
832
833 case CTRL_CLK_PROG_1X_SOURCE_ONE_SOURCE:
834 vf_point_data.board_obj.type =
835 CTRL_CLK_CLK_VF_POINT_TYPE_FREQ;
836 do {
837 clkvfpointfreqmhzset(g, &vf_point_data.vf_point,
838 p1xmaster->super.freq_max_mhz -
839 step_count * freq_step_size_mhz);
840
841 status = _clk_prog_1x_master_rail_construct_vf_point(g, pclk,
842 p1xmaster, p_vf_rail,
843 &vf_point_data.vf_point, &vf_point_idx);
844 if (status) {
845 goto done;
846 }
847 } while (step_count-- > 0);
848 break;
849
850 case CTRL_CLK_PROG_1X_SOURCE_FLL:
851 voltage_min_uv = CLK_FLL_LUT_MIN_VOLTAGE_UV(pclk);
852 voltage_step_size_uv = CLK_FLL_LUT_STEP_SIZE_UV(pclk);
853 step_count = CLK_FLL_LUT_VF_NUM_ENTRIES(pclk);
854
855 /* FLL sources use a voltage-based VF_POINT.*/
856 vf_point_data.board_obj.type =
857 CTRL_CLK_CLK_VF_POINT_TYPE_VOLT;
858 for (i = 0; i < step_count; i++) {
859 vf_point_data.volt.source_voltage_uv =
860 voltage_min_uv + i * voltage_step_size_uv;
861
862 status = _clk_prog_1x_master_rail_construct_vf_point(g, pclk,
863 p1xmaster, p_vf_rail,
864 &vf_point_data.vf_point, &vf_point_idx);
865 if (status) {
866 goto done;
867 }
868 }
869 break;
870 }
871 }
872
873 *pfreqmaxlastmhz = p1xmaster->super.freq_max_mhz;
874
875done:
876 nvgpu_log_info(g, "done status %x", status);
877 return status;
878}
879
880static u32 vflookup_prog_1x_master
881(
882 struct gk20a *g,
883 struct clk_pmupstate *pclk,
884 struct clk_prog_1x_master *p1xmaster,
885 u8 *slave_clk_domain,
886 u16 *pclkmhz,
887 u32 *pvoltuv,
888 u8 rail
889)
890{
891 int j;
892 struct ctrl_clk_clk_prog_1x_master_vf_entry
893 *pvfentry;
894 struct clk_vf_point *pvfpoint;
895 struct clk_progs *pclkprogobjs;
896 struct clk_prog_1x_master_ratio *p1xmasterratio;
897 u16 clkmhz;
898 u32 voltuv;
899 u8 slaveentrycount;
900 int i;
901 struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry *pslaveents;
902
903 if ((*pclkmhz != 0) && (*pvoltuv != 0)) {
904 return -EINVAL;
905 }
906
907 pclkprogobjs = &(pclk->clk_progobjs);
908
909 slaveentrycount = pclkprogobjs->slave_entry_count;
910
911 if (pclkprogobjs->vf_entry_count >
912 CTRL_CLK_CLK_PROG_1X_MASTER_VF_ENTRY_MAX_ENTRIES) {
913 return -EINVAL;
914 }
915
916 if (rail >= pclkprogobjs->vf_entry_count) {
917 return -EINVAL;
918 }
919
920 pvfentry = p1xmaster->p_vf_entries;
921
922 pvfentry = (struct ctrl_clk_clk_prog_1x_master_vf_entry *)(
923 (u8 *)pvfentry +
924 (sizeof(struct ctrl_clk_clk_prog_1x_master_vf_entry) *
925 rail));
926
927 clkmhz = *pclkmhz;
928 voltuv = *pvoltuv;
929
930 /*if domain is slave domain and freq is input
931 then derive master clk */
932 if ((slave_clk_domain != NULL) && (*pclkmhz != 0)) {
933 if (p1xmaster->super.super.super.implements(g,
934 &p1xmaster->super.super.super,
935 CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_RATIO)) {
936
937 p1xmasterratio =
938 (struct clk_prog_1x_master_ratio *)p1xmaster;
939 pslaveents = p1xmasterratio->p_slave_entries;
940 for (i = 0; i < slaveentrycount; i++) {
941 if (pslaveents->clk_dom_idx ==
942 *slave_clk_domain) {
943 break;
944 }
945 pslaveents++;
946 }
947 if (i == slaveentrycount) {
948 return -EINVAL;
949 }
950 clkmhz = (clkmhz * 100)/pslaveents->ratio;
951 } else {
952 /* only support ratio for now */
953 return -EINVAL;
954 }
955 }
956
957 /* if both volt and clks are zero simply print*/
958 if ((*pvoltuv == 0) && (*pclkmhz == 0)) {
959 for (j = pvfentry->vf_point_idx_first;
960 j <= pvfentry->vf_point_idx_last; j++) {
961 pvfpoint = CLK_CLK_VF_POINT_GET(pclk, j);
962 nvgpu_err(g, "v %x c %x",
963 clkvfpointvoltageuvget(g, pvfpoint),
964 clkvfpointfreqmhzget(g, pvfpoint));
965 }
966 return -EINVAL;
967 }
968 /* start looking up f for v for v for f */
969 /* looking for volt? */
970 if (*pvoltuv == 0) {
971 pvfpoint = CLK_CLK_VF_POINT_GET(pclk,
972 pvfentry->vf_point_idx_last);
973 /* above range? */
974 if (clkmhz > clkvfpointfreqmhzget(g, pvfpoint)) {
975 return -EINVAL;
976 }
977
978 for (j = pvfentry->vf_point_idx_last;
979 j >= pvfentry->vf_point_idx_first; j--) {
980 pvfpoint = CLK_CLK_VF_POINT_GET(pclk, j);
981 if (clkmhz <= clkvfpointfreqmhzget(g, pvfpoint)) {
982 voltuv = clkvfpointvoltageuvget(g, pvfpoint);
983 } else {
984 break;
985 }
986 }
987 } else { /* looking for clk? */
988
989 pvfpoint = CLK_CLK_VF_POINT_GET(pclk,
990 pvfentry->vf_point_idx_first);
991 /* below range? */
992 if (voltuv < clkvfpointvoltageuvget(g, pvfpoint)) {
993 return -EINVAL;
994 }
995
996 for (j = pvfentry->vf_point_idx_first;
997 j <= pvfentry->vf_point_idx_last; j++) {
998 pvfpoint = CLK_CLK_VF_POINT_GET(pclk, j);
999 if (voltuv >= clkvfpointvoltageuvget(g, pvfpoint)) {
1000 clkmhz = clkvfpointfreqmhzget(g, pvfpoint);
1001 } else {
1002 break;
1003 }
1004 }
1005 }
1006
1007 /*if domain is slave domain and freq was looked up
1008 then derive slave clk */
1009 if ((slave_clk_domain != NULL) && (*pclkmhz == 0)) {
1010 if (p1xmaster->super.super.super.implements(g,
1011 &p1xmaster->super.super.super,
1012 CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_RATIO)) {
1013
1014 p1xmasterratio =
1015 (struct clk_prog_1x_master_ratio *)p1xmaster;
1016 pslaveents = p1xmasterratio->p_slave_entries;
1017 for (i = 0; i < slaveentrycount; i++) {
1018 if (pslaveents->clk_dom_idx ==
1019 *slave_clk_domain) {
1020 break;
1021 }
1022 pslaveents++;
1023 }
1024 if (i == slaveentrycount) {
1025 return -EINVAL;
1026 }
1027 clkmhz = (clkmhz * pslaveents->ratio)/100;
1028 } else {
1029 /* only support ratio for now */
1030 return -EINVAL;
1031 }
1032 }
1033 *pclkmhz = clkmhz;
1034 *pvoltuv = voltuv;
1035 if ((clkmhz == 0) || (voltuv == 0)) {
1036 return -EINVAL;
1037 }
1038 return 0;
1039}
1040
1041static u32 getfpoints_prog_1x_master
1042(
1043 struct gk20a *g,
1044 struct clk_pmupstate *pclk,
1045 struct clk_prog_1x_master *p1xmaster,
1046 u32 *pfpointscount,
1047 u16 **ppfreqpointsinmhz,
1048 u8 rail
1049)
1050{
1051
1052 struct ctrl_clk_clk_prog_1x_master_vf_entry
1053 *pvfentry;
1054 struct clk_vf_point *pvfpoint;
1055 struct clk_progs *pclkprogobjs;
1056 u8 j;
1057 u32 fpointscount = 0;
1058
1059 if (pfpointscount == NULL) {
1060 return -EINVAL;
1061 }
1062
1063 pclkprogobjs = &(pclk->clk_progobjs);
1064
1065 if (pclkprogobjs->vf_entry_count >
1066 CTRL_CLK_CLK_PROG_1X_MASTER_VF_ENTRY_MAX_ENTRIES) {
1067 return -EINVAL;
1068 }
1069
1070 if (rail >= pclkprogobjs->vf_entry_count) {
1071 return -EINVAL;
1072 }
1073
1074 pvfentry = p1xmaster->p_vf_entries;
1075
1076 pvfentry = (struct ctrl_clk_clk_prog_1x_master_vf_entry *)(
1077 (u8 *)pvfentry +
1078 (sizeof(struct ctrl_clk_clk_prog_1x_master_vf_entry) *
1079 (rail+1)));
1080
1081 fpointscount = pvfentry->vf_point_idx_last -
1082 pvfentry->vf_point_idx_first + 1;
1083
1084 /* if pointer for freq data is NULL simply return count */
1085 if (*ppfreqpointsinmhz == NULL) {
1086 goto done;
1087 }
1088
1089 if (fpointscount > *pfpointscount) {
1090 return -ENOMEM;
1091 }
1092 for (j = pvfentry->vf_point_idx_first;
1093 j <= pvfentry->vf_point_idx_last; j++) {
1094 pvfpoint = CLK_CLK_VF_POINT_GET(pclk, j);
1095 **ppfreqpointsinmhz = clkvfpointfreqmhzget(g, pvfpoint);
1096 (*ppfreqpointsinmhz)++;
1097 }
1098done:
1099 *pfpointscount = fpointscount;
1100 return 0;
1101}
1102
1103static int getslaveclk_prog_1x_master(struct gk20a *g,
1104 struct clk_pmupstate *pclk,
1105 struct clk_prog_1x_master *p1xmaster,
1106 u8 slave_clk_domain,
1107 u16 *pclkmhz,
1108 u16 masterclkmhz
1109)
1110{
1111 struct clk_progs *pclkprogobjs;
1112 struct clk_prog_1x_master_ratio *p1xmasterratio;
1113 u8 slaveentrycount;
1114 u8 i;
1115 struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry *pslaveents;
1116
1117 if (pclkmhz == NULL) {
1118 return -EINVAL;
1119 }
1120
1121 if (masterclkmhz == 0) {
1122 return -EINVAL;
1123 }
1124
1125 *pclkmhz = 0;
1126 pclkprogobjs = &(pclk->clk_progobjs);
1127
1128 slaveentrycount = pclkprogobjs->slave_entry_count;
1129
1130 if (p1xmaster->super.super.super.implements(g,
1131 &p1xmaster->super.super.super,
1132 CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_RATIO)) {
1133 p1xmasterratio =
1134 (struct clk_prog_1x_master_ratio *)p1xmaster;
1135 pslaveents = p1xmasterratio->p_slave_entries;
1136 for (i = 0; i < slaveentrycount; i++) {
1137 if (pslaveents->clk_dom_idx ==
1138 slave_clk_domain) {
1139 break;
1140 }
1141 pslaveents++;
1142 }
1143 if (i == slaveentrycount) {
1144 return -EINVAL;
1145 }
1146 *pclkmhz = (masterclkmhz * pslaveents->ratio)/100;
1147 } else {
1148 /* only support ratio for now */
1149 return -EINVAL;
1150 }
1151 return 0;
1152}