summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/clk/clk_prog.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/nvgpu/clk/clk_prog.c')
-rw-r--r--drivers/gpu/nvgpu/clk/clk_prog.c834
1 files changed, 834 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/clk/clk_prog.c b/drivers/gpu/nvgpu/clk/clk_prog.c
new file mode 100644
index 00000000..d87581c4
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk_prog.c
@@ -0,0 +1,834 @@
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 "clk.h"
16#include "clk_prog.h"
17#include "clk_vf_point.h"
18#include "include/bios.h"
19#include "boardobj/boardobjgrp.h"
20#include "boardobj/boardobjgrp_e32.h"
21#include "pmuif/gpmuifboardobj.h"
22#include "pmuif/gpmuifclk.h"
23#include "gm206/bios_gm206.h"
24#include "ctrl/ctrlclk.h"
25#include "ctrl/ctrlvolt.h"
26#include "gk20a/pmu_gk20a.h"
27
28static struct clk_prog *construct_clk_prog(struct gk20a *g, void *pargs);
29static u32 devinit_get_clk_prog_table(struct gk20a *g,
30 struct clk_progs *pprogobjs);
31static vf_flatten vfflatten_prog_1x_master;
32
33static u32 _clk_progs_pmudatainit(struct gk20a *g,
34 struct boardobjgrp *pboardobjgrp,
35 struct nv_pmu_boardobjgrp_super *pboardobjgrppmu)
36{
37 struct nv_pmu_clk_clk_prog_boardobjgrp_set_header *pset =
38 (struct nv_pmu_clk_clk_prog_boardobjgrp_set_header *)
39 pboardobjgrppmu;
40 struct clk_progs *pprogs = (struct clk_progs *)pboardobjgrp;
41 u32 status = 0;
42
43 status = boardobjgrp_pmudatainit_e32(g, pboardobjgrp, pboardobjgrppmu);
44 if (status) {
45 gk20a_err(dev_from_gk20a(g),
46 "error updating pmu boardobjgrp for clk prog 0x%x",
47 status);
48 goto done;
49 }
50 pset->slave_entry_count = pprogs->slave_entry_count;
51 pset->vf_entry_count = pprogs->vf_entry_count;
52
53done:
54 return status;
55}
56
57static u32 _clk_progs_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_clk_clk_prog_boardobj_grp_set *pgrp_set =
63 (struct nv_pmu_clk_clk_prog_boardobj_grp_set *)pmuboardobjgrp;
64
65 gk20a_dbg_info("");
66
67 /*check whether pmuboardobjgrp has a valid boardobj in index*/
68 if (((u32)BIT(idx) &
69 pgrp_set->hdr.data.super.obj_mask.super.data[0]) == 0)
70 return -EINVAL;
71
72 *ppboardobjpmudata = (struct nv_pmu_boardobj *)
73 &pgrp_set->objects[idx].data.board_obj;
74 gk20a_dbg_info(" Done");
75 return 0;
76}
77
78u32 clk_prog_sw_setup(struct gk20a *g)
79{
80 u32 status;
81 struct boardobjgrp *pboardobjgrp = NULL;
82 struct clk_progs *pclkprogobjs;
83
84 gk20a_dbg_info("");
85
86 status = boardobjgrpconstruct_e255(&g->clk_pmu.clk_progobjs.super);
87 if (status) {
88 gk20a_err(dev_from_gk20a(g),
89 "error creating boardobjgrp for clk prog, status - 0x%x",
90 status);
91 goto done;
92 }
93
94 pboardobjgrp = &g->clk_pmu.clk_progobjs.super.super;
95 pclkprogobjs = &(g->clk_pmu.clk_progobjs);
96
97 BOARDOBJGRP_PMU_CONSTRUCT(pboardobjgrp, CLK, CLK_PROG);
98
99 status = BOARDOBJGRP_PMU_CMD_GRP_SET_CONSTRUCT(g, pboardobjgrp,
100 clk, CLK, clk_prog, CLK_PROG);
101 if (status) {
102 gk20a_err(dev_from_gk20a(g),
103 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
104 status);
105 goto done;
106 }
107
108 pboardobjgrp->pmudatainit = _clk_progs_pmudatainit;
109 pboardobjgrp->pmudatainstget = _clk_progs_pmudata_instget;
110
111 status = devinit_get_clk_prog_table(g, pclkprogobjs);
112 if (status)
113 goto done;
114
115 status = clk_domain_clk_prog_link(g, &g->clk_pmu);
116 if (status) {
117 gk20a_err(dev_from_gk20a(g),
118 "error constructing VF point board objects");
119 goto done;
120 }
121
122
123done:
124 gk20a_dbg_info(" done status %x", status);
125 return status;
126}
127
128u32 clk_prog_pmu_setup(struct gk20a *g)
129{
130 u32 status;
131 struct boardobjgrp *pboardobjgrp = NULL;
132
133 gk20a_dbg_info("");
134
135 pboardobjgrp = &g->clk_pmu.clk_progobjs.super.super;
136
137 if (!pboardobjgrp->bconstructed)
138 return -EINVAL;
139
140 status = pboardobjgrp->pmuinithandle(g, pboardobjgrp);
141
142 gk20a_dbg_info("Done");
143 return status;
144}
145
146static u32 devinit_get_clk_prog_table(struct gk20a *g,
147 struct clk_progs *pclkprogobjs)
148{
149 u32 status = 0;
150 u8 *clkprogs_tbl_ptr = NULL;
151 struct vbios_clock_programming_table_1x_header header = { 0 };
152 struct vbios_clock_programming_table_1x_entry prog = { 0 };
153 struct vbios_clock_programming_table_1x_slave_entry slaveprog = { 0 };
154 struct vbios_clock_programming_table_1x_vf_entry vfprog = { 0 };
155 u8 *entry = NULL;
156 u8 *slaveentry = NULL;
157 u8 *vfentry = NULL;
158 u32 i, j = 0;
159 struct clk_prog *pprog;
160 u8 prog_type;
161 u32 szfmt = VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_SIZE_0D;
162 u32 hszfmt = VBIOS_CLOCK_PROGRAMMING_TABLE_1X_HEADER_SIZE_08;
163 u32 slaveszfmt = VBIOS_CLOCK_PROGRAMMING_TABLE_1X_SLAVE_ENTRY_SIZE_03;
164 u32 vfszfmt = VBIOS_CLOCK_PROGRAMMING_TABLE_1X_VF_ENTRY_SIZE_02;
165 struct ctrl_clk_clk_prog_1x_master_vf_entry
166 vfentries[CTRL_CLK_CLK_PROG_1X_MASTER_VF_ENTRY_MAX_ENTRIES];
167 struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry
168 ratioslaveentries[CTRL_CLK_PROG_1X_MASTER_MAX_SLAVE_ENTRIES];
169 struct ctrl_clk_clk_prog_1x_master_table_slave_entry
170 tableslaveentries[CTRL_CLK_PROG_1X_MASTER_MAX_SLAVE_ENTRIES];
171 union {
172 struct boardobj board_obj;
173 struct clk_prog clkprog;
174 struct clk_prog_1x v1x;
175 struct clk_prog_1x_master v1x_master;
176 struct clk_prog_1x_master_ratio v1x_master_ratio;
177 struct clk_prog_1x_master_table v1x_master_table;
178 } prog_data;
179
180 gk20a_dbg_info("");
181
182 if (g->ops.bios.get_perf_table_ptrs) {
183 clkprogs_tbl_ptr = (u8 *)g->ops.bios.get_perf_table_ptrs(g,
184 g->bios.clock_token, CLOCK_PROGRAMMING_TABLE);
185 if (clkprogs_tbl_ptr == NULL) {
186 status = -EINVAL;
187 goto done;
188 }
189 }
190
191 memcpy(&header, clkprogs_tbl_ptr, hszfmt);
192 if (header.header_size < hszfmt) {
193 status = -EINVAL;
194 goto done;
195 }
196 hszfmt = header.header_size;
197
198 if (header.entry_size <= VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_SIZE_05)
199 szfmt = header.entry_size;
200 else if (header.entry_size <= VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_SIZE_0D)
201 szfmt = header.entry_size;
202 else {
203 status = -EINVAL;
204 goto done;
205 }
206
207 if (header.vf_entry_size < vfszfmt) {
208 status = -EINVAL;
209 goto done;
210 }
211 vfszfmt = header.vf_entry_size;
212 if (header.slave_entry_size < slaveszfmt) {
213 status = -EINVAL;
214 goto done;
215 }
216 slaveszfmt = header.slave_entry_size;
217 if (header.vf_entry_count > CTRL_CLK_CLK_DELTA_MAX_VOLT_RAILS) {
218 status = -EINVAL;
219 goto done;
220 }
221
222 pclkprogobjs->slave_entry_count = header.slave_entry_count;
223 pclkprogobjs->vf_entry_count = header.vf_entry_count;
224
225 for (i = 0; i < header.entry_count; i++) {
226 memset(&prog_data, 0x0, (u32)sizeof(prog_data));
227
228 /* Read table entries*/
229 entry = clkprogs_tbl_ptr + hszfmt +
230 (i * (szfmt + (header.slave_entry_count * slaveszfmt) +
231 (header.vf_entry_count * vfszfmt)));
232
233 memcpy(&prog, entry, szfmt);
234 memset(vfentries, 0xFF,
235 sizeof(struct ctrl_clk_clk_prog_1x_master_vf_entry) *
236 CTRL_CLK_CLK_PROG_1X_MASTER_VF_ENTRY_MAX_ENTRIES);
237 memset(ratioslaveentries, 0xFF,
238 sizeof(struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry) *
239 CTRL_CLK_PROG_1X_MASTER_MAX_SLAVE_ENTRIES);
240 memset(tableslaveentries, 0xFF,
241 sizeof(struct ctrl_clk_clk_prog_1x_master_table_slave_entry) *
242 CTRL_CLK_PROG_1X_MASTER_MAX_SLAVE_ENTRIES);
243 prog_type = (u8)BIOS_GET_FIELD(prog.flags0,
244 NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_SOURCE);
245
246 switch (prog_type) {
247 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_SOURCE_PLL:
248 prog_data.v1x.source = CTRL_CLK_PROG_1X_SOURCE_PLL;
249 prog_data.v1x.source_data.pll.pll_idx =
250 (u8)BIOS_GET_FIELD(prog.param0,
251 NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_PARAM0_PLL_PLL_INDEX);
252 prog_data.v1x.source_data.pll.freq_step_size_mhz =
253 (u8)BIOS_GET_FIELD(prog.param1,
254 NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_PARAM1_PLL_FREQ_STEP_SIZE);
255 break;
256
257 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_SOURCE_ONE_SOURCE:
258 prog_data.v1x.source = CTRL_CLK_PROG_1X_SOURCE_ONE_SOURCE;
259 break;
260
261 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_SOURCE_FLL:
262 prog_data.v1x.source = CTRL_CLK_PROG_1X_SOURCE_FLL;
263 break;
264
265 default:
266 gk20a_err(dev_from_gk20a(g),
267 "invalid source %d", prog_type);
268 status = -EINVAL;
269 goto done;
270 }
271
272 prog_data.v1x.freq_max_mhz = (u16)prog.freq_max_mhz;
273
274 prog_type = (u8)BIOS_GET_FIELD(prog.flags0,
275 NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE);
276
277 vfentry = entry + szfmt +
278 header.slave_entry_count * slaveszfmt;
279 slaveentry = entry + szfmt;
280 switch (prog_type) {
281 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE_MASTER_RATIO:
282 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE_MASTER_TABLE:
283 prog_data.v1x_master.b_o_c_o_v_enabled = false;
284 for (j = 0; j < header.vf_entry_count; j++) {
285 memcpy(&vfprog, vfentry, vfszfmt);
286
287 vfentries[j].vfe_idx = (u8)vfprog.vfe_idx;
288 if (CTRL_CLK_PROG_1X_SOURCE_FLL ==
289 prog_data.v1x.source) {
290 vfentries[j].gain_vfe_idx = (u8)BIOS_GET_FIELD(
291 vfprog.param0,
292 NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_VF_ENTRY_PARAM0_FLL_GAIN_VFE_IDX);
293 } else {
294 vfentries[j].gain_vfe_idx = CTRL_BOARDOBJ_IDX_INVALID;
295 }
296 vfentry += vfszfmt;
297 }
298
299 prog_data.v1x_master.p_vf_entries = vfentries;
300
301 for (j = 0; j < header.slave_entry_count; j++) {
302 memcpy(&slaveprog, slaveentry, slaveszfmt);
303
304 switch (prog_type) {
305 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE_MASTER_RATIO:
306 ratioslaveentries[j].clk_dom_idx =
307 (u8)slaveprog.clk_dom_idx;
308 ratioslaveentries[j].ratio = (u8)
309 BIOS_GET_FIELD(slaveprog.param0,
310 NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_SLAVE_ENTRY_PARAM0_MASTER_RATIO_RATIO);
311 break;
312
313 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE_MASTER_TABLE:
314 tableslaveentries[j].clk_dom_idx =
315 (u8)slaveprog.clk_dom_idx;
316 tableslaveentries[j].freq_mhz =
317 (u16)BIOS_GET_FIELD(slaveprog.param0,
318 NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_SLAVE_ENTRY_PARAM0_MASTER_TABLE_FREQ);
319 break;
320 }
321 slaveentry += slaveszfmt;
322 }
323
324 switch (prog_type) {
325 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE_MASTER_RATIO:
326 prog_data.board_obj.type = CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_RATIO;
327 prog_data.v1x_master_ratio.p_slave_entries =
328 ratioslaveentries;
329 break;
330
331 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE_MASTER_TABLE:
332 prog_data.board_obj.type = CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_TABLE;
333
334 prog_data.v1x_master_table.p_slave_entries =
335 tableslaveentries;
336 break;
337
338 }
339 break;
340
341 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE_SLAVE:
342 prog_data.board_obj.type = CTRL_CLK_CLK_PROG_TYPE_1X;
343 break;
344
345
346 default:
347 gk20a_err(dev_from_gk20a(g),
348 "source issue %d", prog_type);
349 status = -EINVAL;
350 goto done;
351 }
352
353 pprog = construct_clk_prog(g, (void *)&prog_data);
354 if (pprog == NULL) {
355 gk20a_err(dev_from_gk20a(g),
356 "error constructing clk_prog boardobj %d", i);
357 status = -EINVAL;
358 goto done;
359 }
360
361 status = boardobjgrp_objinsert(&pclkprogobjs->super.super,
362 (struct boardobj *)pprog, i);
363 if (status) {
364 gk20a_err(dev_from_gk20a(g),
365 "error adding clk_prog boardobj %d", i);
366 status = -EINVAL;
367 goto done;
368 }
369 }
370done:
371 gk20a_dbg_info(" done status %x", status);
372 return status;
373}
374
375static u32 _clk_prog_pmudatainit_super(struct gk20a *g,
376 struct boardobj *board_obj_ptr,
377 struct nv_pmu_boardobj *ppmudata)
378{
379 u32 status = 0;
380
381 gk20a_dbg_info("");
382
383 status = boardobj_pmudatainit_super(g, board_obj_ptr, ppmudata);
384 return status;
385}
386
387static u32 _clk_prog_pmudatainit_1x(struct gk20a *g,
388 struct boardobj *board_obj_ptr,
389 struct nv_pmu_boardobj *ppmudata)
390{
391 u32 status = 0;
392 struct clk_prog_1x *pclk_prog_1x;
393 struct nv_pmu_clk_clk_prog_1x_boardobj_set *pset;
394
395 gk20a_dbg_info("");
396
397 status = _clk_prog_pmudatainit_super(g, board_obj_ptr, ppmudata);
398 if (status != 0)
399 return status;
400
401 pclk_prog_1x = (struct clk_prog_1x *)board_obj_ptr;
402
403 pset = (struct nv_pmu_clk_clk_prog_1x_boardobj_set *)
404 ppmudata;
405
406 pset->source = pclk_prog_1x->source;
407 pset->freq_max_mhz = pclk_prog_1x->freq_max_mhz;
408 pset->source_data = pclk_prog_1x->source_data;
409
410 return status;
411}
412
413static u32 _clk_prog_pmudatainit_1x_master(struct gk20a *g,
414 struct boardobj *board_obj_ptr,
415 struct nv_pmu_boardobj *ppmudata)
416{
417 u32 status = 0;
418 struct clk_prog_1x_master *pclk_prog_1x_master;
419 struct nv_pmu_clk_clk_prog_1x_master_boardobj_set *pset;
420 u32 vfsize = sizeof(struct ctrl_clk_clk_prog_1x_master_vf_entry) *
421 g->clk_pmu.clk_progobjs.vf_entry_count;
422
423 gk20a_dbg_info("");
424
425 status = _clk_prog_pmudatainit_1x(g, board_obj_ptr, ppmudata);
426
427 pclk_prog_1x_master =
428 (struct clk_prog_1x_master *)board_obj_ptr;
429
430 pset = (struct nv_pmu_clk_clk_prog_1x_master_boardobj_set *)
431 ppmudata;
432
433 memcpy(pset->vf_entries, pclk_prog_1x_master->p_vf_entries, vfsize);
434
435 pset->b_o_c_o_v_enabled = pclk_prog_1x_master->b_o_c_o_v_enabled;
436
437 memcpy(&pset->deltas, &pclk_prog_1x_master->deltas,
438 (u32) sizeof(struct ctrl_clk_clk_delta));
439
440 return status;
441}
442
443static u32 _clk_prog_pmudatainit_1x_master_ratio(struct gk20a *g,
444 struct boardobj *board_obj_ptr,
445 struct nv_pmu_boardobj *ppmudata)
446{
447 u32 status = 0;
448 struct clk_prog_1x_master_ratio *pclk_prog_1x_master_ratio;
449 struct nv_pmu_clk_clk_prog_1x_master_ratio_boardobj_set *pset;
450 u32 slavesize = sizeof(struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry) *
451 g->clk_pmu.clk_progobjs.slave_entry_count;
452
453 gk20a_dbg_info("");
454
455 status = _clk_prog_pmudatainit_1x_master(g, board_obj_ptr, ppmudata);
456 if (status != 0)
457 return status;
458
459 pclk_prog_1x_master_ratio =
460 (struct clk_prog_1x_master_ratio *)board_obj_ptr;
461
462 pset = (struct nv_pmu_clk_clk_prog_1x_master_ratio_boardobj_set *)
463 ppmudata;
464
465 memcpy(pset->slave_entries,
466 pclk_prog_1x_master_ratio->p_slave_entries, slavesize);
467
468 return status;
469}
470
471static u32 _clk_prog_pmudatainit_1x_master_table(struct gk20a *g,
472 struct boardobj *board_obj_ptr,
473 struct nv_pmu_boardobj *ppmudata)
474{
475 u32 status = 0;
476 struct clk_prog_1x_master_table *pclk_prog_1x_master_table;
477 struct nv_pmu_clk_clk_prog_1x_master_table_boardobj_set *pset;
478 u32 slavesize = sizeof(struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry) *
479 g->clk_pmu.clk_progobjs.slave_entry_count;
480
481 gk20a_dbg_info("");
482
483 status = _clk_prog_pmudatainit_1x_master(g, board_obj_ptr, ppmudata);
484 if (status != 0)
485 return status;
486
487 pclk_prog_1x_master_table =
488 (struct clk_prog_1x_master_table *)board_obj_ptr;
489
490 pset = (struct nv_pmu_clk_clk_prog_1x_master_table_boardobj_set *)
491 ppmudata;
492 memcpy(pset->slave_entries,
493 pclk_prog_1x_master_table->p_slave_entries, slavesize);
494
495 return status;
496}
497
498static u32 _clk_prog_1x_master_rail_construct_vf_point(struct gk20a *g,
499 struct clk_pmupstate *pclk,
500 struct clk_prog_1x_master *p1xmaster,
501 struct ctrl_clk_clk_prog_1x_master_vf_entry *p_vf_rail,
502 struct clk_vf_point *p_vf_point_tmp,
503 u8 *p_vf_point_idx)
504{
505 struct clk_vf_point *p_vf_point;
506 u32 status;
507
508 gk20a_dbg_info("");
509
510 p_vf_point = construct_clk_vf_point(g, (void *)p_vf_point_tmp);
511 if (p_vf_point == NULL) {
512 status = -ENOMEM;
513 goto done;
514 }
515 status = pclk->clk_vf_pointobjs.super.super.objinsert(
516 &pclk->clk_vf_pointobjs.super.super,
517 &p_vf_point->super,
518 *p_vf_point_idx);
519 if (status)
520 goto done;
521
522 p_vf_rail->vf_point_idx_last = (*p_vf_point_idx)++;
523
524done:
525 gk20a_dbg_info("done status %x", status);
526 return status;
527}
528
529static u32 clk_prog_construct_super(struct gk20a *g,
530 struct boardobj **ppboardobj,
531 u16 size, void *pargs)
532{
533 struct clk_prog *pclkprog;
534 u32 status = 0;
535
536 status = boardobj_construct_super(g, ppboardobj,
537 size, pargs);
538 if (status)
539 return -EINVAL;
540
541 pclkprog = (struct clk_prog *)*ppboardobj;
542
543 pclkprog->super.pmudatainit =
544 _clk_prog_pmudatainit_super;
545 return status;
546}
547
548
549static u32 clk_prog_construct_1x(struct gk20a *g,
550 struct boardobj **ppboardobj,
551 u16 size, void *pargs)
552{
553 struct boardobj *ptmpobj = (struct boardobj *)pargs;
554 struct clk_prog_1x *pclkprog;
555 struct clk_prog_1x *ptmpprog =
556 (struct clk_prog_1x *)pargs;
557 u32 status = 0;
558
559 gk20a_dbg_info(" ");
560 ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_PROG_TYPE_1X);
561 status = clk_prog_construct_super(g, ppboardobj, size, pargs);
562 if (status)
563 return -EINVAL;
564
565 pclkprog = (struct clk_prog_1x *)*ppboardobj;
566
567 pclkprog->super.super.pmudatainit =
568 _clk_prog_pmudatainit_1x;
569
570 pclkprog->source = ptmpprog->source;
571 pclkprog->freq_max_mhz = ptmpprog->freq_max_mhz;
572 pclkprog->source_data = ptmpprog->source_data;
573
574 return status;
575}
576
577static u32 clk_prog_construct_1x_master(struct gk20a *g,
578 struct boardobj **ppboardobj,
579 u16 size, void *pargs)
580{
581 struct boardobj *ptmpobj = (struct boardobj *)pargs;
582 struct clk_prog_1x_master *pclkprog;
583 struct clk_prog_1x_master *ptmpprog =
584 (struct clk_prog_1x_master *)pargs;
585 u32 status = 0;
586 u32 vfsize = sizeof(struct ctrl_clk_clk_prog_1x_master_vf_entry) *
587 g->clk_pmu.clk_progobjs.vf_entry_count;
588 u8 railidx;
589
590 gk20a_dbg_info(" type - %x", BOARDOBJ_GET_TYPE(pargs));
591
592 ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_PROG_TYPE_1X_MASTER);
593 status = clk_prog_construct_1x(g, ppboardobj, size, pargs);
594 if (status)
595 return -EINVAL;
596
597 pclkprog = (struct clk_prog_1x_master *)*ppboardobj;
598
599 pclkprog->super.super.super.pmudatainit =
600 _clk_prog_pmudatainit_1x_master;
601
602 pclkprog->vfflatten =
603 vfflatten_prog_1x_master;
604
605 pclkprog->p_vf_entries = (struct ctrl_clk_clk_prog_1x_master_vf_entry *)
606 kzalloc(vfsize, GFP_KERNEL);
607
608 memcpy(pclkprog->p_vf_entries, ptmpprog->p_vf_entries, vfsize);
609
610 pclkprog->b_o_c_o_v_enabled = ptmpprog->b_o_c_o_v_enabled;
611
612 for (railidx = 0;
613 railidx < g->clk_pmu.clk_progobjs.vf_entry_count;
614 railidx++) {
615 pclkprog->p_vf_entries[railidx].vf_point_idx_first =
616 CTRL_CLK_CLK_VF_POINT_IDX_INVALID;
617 pclkprog->p_vf_entries[railidx].vf_point_idx_last =
618 CTRL_CLK_CLK_VF_POINT_IDX_INVALID;
619 }
620
621 return status;
622}
623
624static u32 clk_prog_construct_1x_master_ratio(struct gk20a *g,
625 struct boardobj **ppboardobj,
626 u16 size, void *pargs)
627{
628 struct boardobj *ptmpobj = (struct boardobj *)pargs;
629 struct clk_prog_1x_master_ratio *pclkprog;
630 struct clk_prog_1x_master_ratio *ptmpprog =
631 (struct clk_prog_1x_master_ratio *)pargs;
632 u32 status = 0;
633 u32 slavesize = sizeof(struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry) *
634 g->clk_pmu.clk_progobjs.slave_entry_count;
635
636 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_RATIO)
637 return -EINVAL;
638
639 ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_RATIO);
640 status = clk_prog_construct_1x_master(g, ppboardobj, size, pargs);
641 if (status)
642 return -EINVAL;
643
644 pclkprog = (struct clk_prog_1x_master_ratio *)*ppboardobj;
645
646 pclkprog->super.super.super.super.pmudatainit =
647 _clk_prog_pmudatainit_1x_master_ratio;
648
649 pclkprog->p_slave_entries =
650 (struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry *)
651 kzalloc(slavesize, GFP_KERNEL);
652 if (!pclkprog->p_slave_entries)
653 return -ENOMEM;
654
655 memset(pclkprog->p_slave_entries, CTRL_CLK_CLK_DOMAIN_INDEX_INVALID,
656 slavesize);
657
658 memcpy(pclkprog->p_slave_entries, ptmpprog->p_slave_entries, slavesize);
659
660 return status;
661}
662
663static u32 clk_prog_construct_1x_master_table(struct gk20a *g,
664 struct boardobj **ppboardobj,
665 u16 size, void *pargs)
666{
667 struct boardobj *ptmpobj = (struct boardobj *)pargs;
668 struct clk_prog_1x_master_table *pclkprog;
669 struct clk_prog_1x_master_table *ptmpprog =
670 (struct clk_prog_1x_master_table *)pargs;
671 u32 status = 0;
672 u32 slavesize = sizeof(struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry) *
673 g->clk_pmu.clk_progobjs.slave_entry_count;
674
675 gk20a_dbg_info("type - %x", BOARDOBJ_GET_TYPE(pargs));
676
677 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_TABLE)
678 return -EINVAL;
679
680 ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_TABLE);
681 status = clk_prog_construct_1x_master(g, ppboardobj, size, pargs);
682 if (status)
683 return -EINVAL;
684
685 pclkprog = (struct clk_prog_1x_master_table *)*ppboardobj;
686
687 pclkprog->super.super.super.super.pmudatainit =
688 _clk_prog_pmudatainit_1x_master_table;
689
690 pclkprog->p_slave_entries =
691 (struct ctrl_clk_clk_prog_1x_master_table_slave_entry *)
692 kzalloc(slavesize, GFP_KERNEL);
693 if (!pclkprog->p_slave_entries)
694 return -ENOMEM;
695
696 memset(pclkprog->p_slave_entries, CTRL_CLK_CLK_DOMAIN_INDEX_INVALID,
697 slavesize);
698
699 memcpy(pclkprog->p_slave_entries, ptmpprog->p_slave_entries, slavesize);
700
701 return status;
702}
703
704static struct clk_prog *construct_clk_prog(struct gk20a *g, void *pargs)
705{
706 struct boardobj *board_obj_ptr = NULL;
707 u32 status;
708
709 gk20a_dbg_info(" type - %x", BOARDOBJ_GET_TYPE(pargs));
710 switch (BOARDOBJ_GET_TYPE(pargs)) {
711 case CTRL_CLK_CLK_PROG_TYPE_1X:
712 status = clk_prog_construct_1x(g, &board_obj_ptr,
713 sizeof(struct clk_prog_1x), pargs);
714 break;
715
716 case CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_TABLE:
717 status = clk_prog_construct_1x_master_table(g, &board_obj_ptr,
718 sizeof(struct clk_prog_1x_master_table), pargs);
719 break;
720
721 case CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_RATIO:
722 status = clk_prog_construct_1x_master_ratio(g, &board_obj_ptr,
723 sizeof(struct clk_prog_1x_master_ratio), pargs);
724 break;
725
726 default:
727 return NULL;
728 }
729
730 if (status)
731 return NULL;
732
733 gk20a_dbg_info(" Done");
734
735 return (struct clk_prog *)board_obj_ptr;
736}
737
738static u32 vfflatten_prog_1x_master(struct gk20a *g,
739 struct clk_pmupstate *pclk,
740 struct clk_prog_1x_master *p1xmaster,
741 u8 clk_domain_idx, u16 *pfreqmaxlastmhz)
742{
743 struct ctrl_clk_clk_prog_1x_master_vf_entry *p_vf_rail;
744 union {
745 struct boardobj board_obj;
746 struct clk_vf_point vf_point;
747 struct clk_vf_point_freq freq;
748 struct clk_vf_point_volt volt;
749 } vf_point_data;
750 u32 status = 0;
751 u8 step_count;
752 u8 freq_step_size_mhz = 0;
753 u8 vf_point_idx;
754 u8 vf_rail_idx;
755
756 gk20a_dbg_info("");
757 memset(&vf_point_data, 0x0, sizeof(vf_point_data));
758
759 vf_point_idx = BOARDOBJGRP_NEXT_EMPTY_IDX(
760 &pclk->clk_vf_pointobjs.super.super);
761
762 for (vf_rail_idx = 0;
763 vf_rail_idx < pclk->clk_progobjs.vf_entry_count;
764 vf_rail_idx++) {
765 u32 voltage_min_uv;
766 u32 voltage_step_size_uv;
767 u8 i;
768
769 p_vf_rail = &p1xmaster->p_vf_entries[vf_rail_idx];
770 if (p_vf_rail->vfe_idx == CTRL_BOARDOBJ_IDX_INVALID)
771 continue;
772
773 p_vf_rail->vf_point_idx_first = vf_point_idx;
774
775 vf_point_data.vf_point.vfe_equ_idx = p_vf_rail->vfe_idx;
776 vf_point_data.vf_point.volt_rail_idx = vf_rail_idx;
777
778 step_count = 0;
779
780 switch (p1xmaster->super.source) {
781 case CTRL_CLK_PROG_1X_SOURCE_PLL:
782 freq_step_size_mhz =
783 p1xmaster->super.source_data.pll.freq_step_size_mhz;
784 step_count = (freq_step_size_mhz == 0) ? 0 :
785 (p1xmaster->super.freq_max_mhz - *pfreqmaxlastmhz - 1) /
786 freq_step_size_mhz;
787 /* Intentional fall-through.*/
788
789 case CTRL_CLK_PROG_1X_SOURCE_ONE_SOURCE:
790 vf_point_data.board_obj.type =
791 CTRL_CLK_CLK_VF_POINT_TYPE_FREQ;
792 do {
793 clkvfpointfreqmhzset(g, &vf_point_data.vf_point,
794 p1xmaster->super.freq_max_mhz -
795 step_count * freq_step_size_mhz);
796
797 status = _clk_prog_1x_master_rail_construct_vf_point(g, pclk,
798 p1xmaster, p_vf_rail,
799 &vf_point_data.vf_point, &vf_point_idx);
800 if (status)
801 goto done;
802 } while (step_count-- > 0);
803 break;
804
805 case CTRL_CLK_PROG_1X_SOURCE_FLL:
806 voltage_min_uv = CLK_FLL_LUT_MIN_VOLTAGE_UV(pclk);
807 voltage_step_size_uv = CLK_FLL_LUT_STEP_SIZE_UV(pclk);
808 step_count = CLK_FLL_LUT_VF_NUM_ENTRIES(pclk);
809
810 /* FLL sources use a voltage-based VF_POINT.*/
811 vf_point_data.board_obj.type =
812 CTRL_CLK_CLK_VF_POINT_TYPE_VOLT;
813 vf_point_data.volt.clk_domain_idx = clk_domain_idx;
814 for (i = 0; i < step_count; i++) {
815 vf_point_data.volt.source_voltage_uv =
816 voltage_min_uv + i * voltage_step_size_uv;
817 vf_point_data.volt.vf_gain_vfe_equ_idx = p_vf_rail->gain_vfe_idx;
818
819 status = _clk_prog_1x_master_rail_construct_vf_point(g, pclk,
820 p1xmaster, p_vf_rail,
821 &vf_point_data.vf_point, &vf_point_idx);
822 if (status)
823 goto done;
824 }
825 break;
826 }
827 }
828
829 *pfreqmaxlastmhz = p1xmaster->super.freq_max_mhz;
830
831done:
832 gk20a_dbg_info("done status %x", status);
833 return status;
834}