summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/clk/clk_domain.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/nvgpu/clk/clk_domain.c')
-rw-r--r--drivers/gpu/nvgpu/clk/clk_domain.c1118
1 files changed, 1118 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/clk/clk_domain.c b/drivers/gpu/nvgpu/clk/clk_domain.c
new file mode 100644
index 00000000..dbbf4d4a
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk_domain.c
@@ -0,0 +1,1118 @@
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 "clk.h"
27#include "clk_fll.h"
28#include "clk_domain.h"
29#include "boardobj/boardobjgrp.h"
30#include "boardobj/boardobjgrp_e32.h"
31#include "ctrl/ctrlclk.h"
32#include "ctrl/ctrlvolt.h"
33
34static struct clk_domain *construct_clk_domain(struct gk20a *g, void *pargs);
35
36static u32 devinit_get_clocks_table(struct gk20a *g,
37 struct clk_domains *pdomainobjs);
38
39static u32 clk_domain_pmudatainit_super(struct gk20a *g, struct boardobj
40 *board_obj_ptr, struct nv_pmu_boardobj *ppmudata);
41
42static const struct vbios_clocks_table_1x_hal_clock_entry
43 vbiosclktbl1xhalentry[] = {
44 { clkwhich_gpc2clk, true, },
45 { clkwhich_xbar2clk, true, },
46 { clkwhich_mclk, false, },
47 { clkwhich_sys2clk, true, },
48 { clkwhich_hub2clk, false, },
49 { clkwhich_nvdclk, false, },
50 { clkwhich_pwrclk, false, },
51 { clkwhich_dispclk, false, },
52 { clkwhich_pciegenclk, false, }
53};
54
55static u32 clktranslatehalmumsettoapinumset(u32 clkhaldomains)
56{
57 u32 clkapidomains = 0;
58
59 if (clkhaldomains & BIT(clkwhich_gpc2clk))
60 clkapidomains |= CTRL_CLK_DOMAIN_GPC2CLK;
61 if (clkhaldomains & BIT(clkwhich_xbar2clk))
62 clkapidomains |= CTRL_CLK_DOMAIN_XBAR2CLK;
63 if (clkhaldomains & BIT(clkwhich_sys2clk))
64 clkapidomains |= CTRL_CLK_DOMAIN_SYS2CLK;
65 if (clkhaldomains & BIT(clkwhich_hub2clk))
66 clkapidomains |= CTRL_CLK_DOMAIN_HUB2CLK;
67 if (clkhaldomains & BIT(clkwhich_pwrclk))
68 clkapidomains |= CTRL_CLK_DOMAIN_PWRCLK;
69 if (clkhaldomains & BIT(clkwhich_pciegenclk))
70 clkapidomains |= CTRL_CLK_DOMAIN_PCIEGENCLK;
71 if (clkhaldomains & BIT(clkwhich_mclk))
72 clkapidomains |= CTRL_CLK_DOMAIN_MCLK;
73 if (clkhaldomains & BIT(clkwhich_nvdclk))
74 clkapidomains |= CTRL_CLK_DOMAIN_NVDCLK;
75 if (clkhaldomains & BIT(clkwhich_dispclk))
76 clkapidomains |= CTRL_CLK_DOMAIN_DISPCLK;
77
78 return clkapidomains;
79}
80
81static u32 _clk_domains_pmudatainit_3x(struct gk20a *g,
82 struct boardobjgrp *pboardobjgrp,
83 struct nv_pmu_boardobjgrp_super *pboardobjgrppmu)
84{
85 struct nv_pmu_clk_clk_domain_boardobjgrp_set_header *pset =
86 (struct nv_pmu_clk_clk_domain_boardobjgrp_set_header *)
87 pboardobjgrppmu;
88 struct clk_domains *pdomains = (struct clk_domains *)pboardobjgrp;
89 u32 status = 0;
90
91 status = boardobjgrp_pmudatainit_e32(g, pboardobjgrp, pboardobjgrppmu);
92 if (status) {
93 nvgpu_err(g,
94 "error updating pmu boardobjgrp for clk domain 0x%x",
95 status);
96 goto done;
97 }
98
99 pset->vbios_domains = pdomains->vbios_domains;
100 pset->cntr_sampling_periodms = pdomains->cntr_sampling_periodms;
101 pset->b_override_o_v_o_c = false;
102 pset->b_debug_mode = false;
103 pset->b_enforce_vf_monotonicity = pdomains->b_enforce_vf_monotonicity;
104 pset->b_enforce_vf_smoothening = pdomains->b_enforce_vf_smoothening;
105 pset->volt_rails_max = 2;
106 status = boardobjgrpmask_export(
107 &pdomains->master_domains_mask.super,
108 pdomains->master_domains_mask.super.bitcount,
109 &pset->master_domains_mask.super);
110
111 memcpy(&pset->deltas, &pdomains->deltas,
112 (sizeof(struct ctrl_clk_clk_delta)));
113
114done:
115 return status;
116}
117
118static u32 _clk_domains_pmudata_instget(struct gk20a *g,
119 struct nv_pmu_boardobjgrp *pmuboardobjgrp,
120 struct nv_pmu_boardobj **ppboardobjpmudata,
121 u8 idx)
122{
123 struct nv_pmu_clk_clk_domain_boardobj_grp_set *pgrp_set =
124 (struct nv_pmu_clk_clk_domain_boardobj_grp_set *)
125 pmuboardobjgrp;
126
127 gk20a_dbg_info("");
128
129 /*check whether pmuboardobjgrp has a valid boardobj in index*/
130 if (((u32)BIT(idx) &
131 pgrp_set->hdr.data.super.obj_mask.super.data[0]) == 0)
132 return -EINVAL;
133
134 *ppboardobjpmudata = (struct nv_pmu_boardobj *)
135 &pgrp_set->objects[idx].data.board_obj;
136 gk20a_dbg_info(" Done");
137 return 0;
138}
139
140u32 clk_domain_sw_setup(struct gk20a *g)
141{
142 u32 status;
143 struct boardobjgrp *pboardobjgrp = NULL;
144 struct clk_domains *pclkdomainobjs;
145 struct clk_domain *pdomain;
146 struct clk_domain_3x_master *pdomain_master;
147 struct clk_domain_3x_slave *pdomain_slave;
148 u8 i;
149
150 gk20a_dbg_info("");
151
152 status = boardobjgrpconstruct_e32(g, &g->clk_pmu.clk_domainobjs.super);
153 if (status) {
154 nvgpu_err(g,
155 "error creating boardobjgrp for clk domain, status - 0x%x",
156 status);
157 goto done;
158 }
159
160 pboardobjgrp = &g->clk_pmu.clk_domainobjs.super.super;
161 pclkdomainobjs = &(g->clk_pmu.clk_domainobjs);
162
163 BOARDOBJGRP_PMU_CONSTRUCT(pboardobjgrp, CLK, CLK_DOMAIN);
164
165 status = BOARDOBJGRP_PMU_CMD_GRP_SET_CONSTRUCT(g, pboardobjgrp,
166 clk, CLK, clk_domain, CLK_DOMAIN);
167 if (status) {
168 nvgpu_err(g,
169 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
170 status);
171 goto done;
172 }
173
174 pboardobjgrp->pmudatainit = _clk_domains_pmudatainit_3x;
175 pboardobjgrp->pmudatainstget = _clk_domains_pmudata_instget;
176
177 /* Initialize mask to zero.*/
178 boardobjgrpmask_e32_init(&pclkdomainobjs->prog_domains_mask, NULL);
179 boardobjgrpmask_e32_init(&pclkdomainobjs->master_domains_mask, NULL);
180 pclkdomainobjs->b_enforce_vf_monotonicity = true;
181 pclkdomainobjs->b_enforce_vf_smoothening = true;
182
183 memset(&pclkdomainobjs->ordered_noise_aware_list, 0,
184 sizeof(pclkdomainobjs->ordered_noise_aware_list));
185
186 memset(&pclkdomainobjs->ordered_noise_unaware_list, 0,
187 sizeof(pclkdomainobjs->ordered_noise_unaware_list));
188
189 memset(&pclkdomainobjs->deltas, 0,
190 sizeof(struct ctrl_clk_clk_delta));
191
192 status = devinit_get_clocks_table(g, pclkdomainobjs);
193 if (status)
194 goto done;
195
196 BOARDOBJGRP_FOR_EACH(&(pclkdomainobjs->super.super),
197 struct clk_domain *, pdomain, i) {
198 pdomain_master = NULL;
199 if (pdomain->super.implements(g, &pdomain->super,
200 CTRL_CLK_CLK_DOMAIN_TYPE_3X_PROG)) {
201 status = boardobjgrpmask_bitset(
202 &pclkdomainobjs->prog_domains_mask.super, i);
203 if (status)
204 goto done;
205 }
206
207 if (pdomain->super.implements(g, &pdomain->super,
208 CTRL_CLK_CLK_DOMAIN_TYPE_3X_MASTER)) {
209 status = boardobjgrpmask_bitset(
210 &pclkdomainobjs->master_domains_mask.super, i);
211 if (status)
212 goto done;
213 }
214
215 if (pdomain->super.implements(g, &pdomain->super,
216 CTRL_CLK_CLK_DOMAIN_TYPE_3X_SLAVE)) {
217 pdomain_slave =
218 (struct clk_domain_3x_slave *)pdomain;
219 pdomain_master =
220 (struct clk_domain_3x_master *)
221 (CLK_CLK_DOMAIN_GET((&g->clk_pmu),
222 pdomain_slave->master_idx));
223 pdomain_master->slave_idxs_mask |= BIT(i);
224 }
225
226 }
227
228done:
229 gk20a_dbg_info(" done status %x", status);
230 return status;
231}
232
233u32 clk_domain_pmu_setup(struct gk20a *g)
234{
235 u32 status;
236 struct boardobjgrp *pboardobjgrp = NULL;
237
238 gk20a_dbg_info("");
239
240 pboardobjgrp = &g->clk_pmu.clk_domainobjs.super.super;
241
242 if (!pboardobjgrp->bconstructed)
243 return -EINVAL;
244
245 status = pboardobjgrp->pmuinithandle(g, pboardobjgrp);
246
247 gk20a_dbg_info("Done");
248 return status;
249}
250
251static u32 devinit_get_clocks_table(struct gk20a *g,
252 struct clk_domains *pclkdomainobjs)
253{
254 u32 status = 0;
255 u8 *clocks_table_ptr = NULL;
256 struct vbios_clocks_table_1x_header clocks_table_header = { 0 };
257 struct vbios_clocks_table_1x_entry clocks_table_entry = { 0 };
258 u8 *clocks_tbl_entry_ptr = NULL;
259 u32 index = 0;
260 struct clk_domain *pclkdomain_dev;
261 union {
262 struct boardobj boardobj;
263 struct clk_domain clk_domain;
264 struct clk_domain_3x v3x;
265 struct clk_domain_3x_fixed v3x_fixed;
266 struct clk_domain_3x_prog v3x_prog;
267 struct clk_domain_3x_master v3x_master;
268 struct clk_domain_3x_slave v3x_slave;
269 } clk_domain_data;
270
271 gk20a_dbg_info("");
272
273 clocks_table_ptr = (u8 *)nvgpu_bios_get_perf_table_ptrs(g,
274 g->bios.clock_token, CLOCKS_TABLE);
275 if (clocks_table_ptr == NULL) {
276 status = -EINVAL;
277 goto done;
278 }
279
280 memcpy(&clocks_table_header, clocks_table_ptr,
281 VBIOS_CLOCKS_TABLE_1X_HEADER_SIZE_07);
282 if (clocks_table_header.header_size <
283 VBIOS_CLOCKS_TABLE_1X_HEADER_SIZE_07) {
284 status = -EINVAL;
285 goto done;
286 }
287
288 if (clocks_table_header.entry_size <
289 VBIOS_CLOCKS_TABLE_1X_ENTRY_SIZE_09) {
290 status = -EINVAL;
291 goto done;
292 }
293
294 pclkdomainobjs->cntr_sampling_periodms =
295 (u16)clocks_table_header.cntr_sampling_periodms;
296
297 /* Read table entries*/
298 clocks_tbl_entry_ptr = clocks_table_ptr +
299 VBIOS_CLOCKS_TABLE_1X_HEADER_SIZE_07;
300 for (index = 0; index < clocks_table_header.entry_count; index++) {
301 memcpy(&clocks_table_entry, clocks_tbl_entry_ptr,
302 clocks_table_header.entry_size);
303 clk_domain_data.clk_domain.domain =
304 vbiosclktbl1xhalentry[index].domain;
305 clk_domain_data.clk_domain.api_domain =
306 clktranslatehalmumsettoapinumset(
307 BIT(clk_domain_data.clk_domain.domain));
308 clk_domain_data.v3x.b_noise_aware_capable =
309 vbiosclktbl1xhalentry[index].b_noise_aware_capable;
310
311 switch (BIOS_GET_FIELD(clocks_table_entry.flags0,
312 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_FLAGS0_USAGE)) {
313 case NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_FLAGS0_USAGE_FIXED:
314 clk_domain_data.boardobj.type =
315 CTRL_CLK_CLK_DOMAIN_TYPE_3X_FIXED;
316 clk_domain_data.v3x_fixed.freq_mhz = (u16)BIOS_GET_FIELD(
317 clocks_table_entry.param1,
318 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM1_FIXED_FREQUENCY_MHZ);
319 break;
320
321 case NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_FLAGS0_USAGE_MASTER:
322 clk_domain_data.boardobj.type =
323 CTRL_CLK_CLK_DOMAIN_TYPE_3X_MASTER;
324 clk_domain_data.v3x_prog.clk_prog_idx_first =
325 (u8)(BIOS_GET_FIELD(clocks_table_entry.param0,
326 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM0_PROG_CLK_PROG_IDX_FIRST));
327 clk_domain_data.v3x_prog.clk_prog_idx_last =
328 (u8)(BIOS_GET_FIELD(clocks_table_entry.param0,
329 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM0_PROG_CLK_PROG_IDX_LAST));
330 clk_domain_data.v3x_prog.noise_unaware_ordering_index =
331 (u8)(BIOS_GET_FIELD(clocks_table_entry.param2,
332 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM2_PROG_NOISE_UNAWARE_ORDERING_IDX));
333
334 if (clk_domain_data.v3x.b_noise_aware_capable) {
335 clk_domain_data.v3x_prog.noise_aware_ordering_index =
336 (u8)(BIOS_GET_FIELD(clocks_table_entry.param2,
337 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM2_PROG_NOISE_AWARE_ORDERING_IDX));
338 clk_domain_data.v3x_prog.b_force_noise_unaware_ordering =
339 (u8)(BIOS_GET_FIELD(clocks_table_entry.param2,
340 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM2_PROG_FORCE_NOISE_UNAWARE_ORDERING));
341 } else {
342 clk_domain_data.v3x_prog.noise_aware_ordering_index =
343 CTRL_CLK_CLK_DOMAIN_3X_PROG_ORDERING_INDEX_INVALID;
344 clk_domain_data.v3x_prog.b_force_noise_unaware_ordering = false;
345 }
346 clk_domain_data.v3x_prog.factory_offset_khz = 0;
347
348 clk_domain_data.v3x_prog.freq_delta_min_mhz =
349 (u16)(BIOS_GET_FIELD(clocks_table_entry.param1,
350 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM1_MASTER_FREQ_OC_DELTA_MIN_MHZ));
351
352 clk_domain_data.v3x_prog.freq_delta_max_mhz =
353 (u16)(BIOS_GET_FIELD(clocks_table_entry.param1,
354 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM1_MASTER_FREQ_OC_DELTA_MAX_MHZ));
355 break;
356
357 case NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_FLAGS0_USAGE_SLAVE:
358 clk_domain_data.boardobj.type =
359 CTRL_CLK_CLK_DOMAIN_TYPE_3X_SLAVE;
360 clk_domain_data.v3x_prog.clk_prog_idx_first =
361 (u8)(BIOS_GET_FIELD(clocks_table_entry.param0,
362 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM0_PROG_CLK_PROG_IDX_FIRST));
363 clk_domain_data.v3x_prog.clk_prog_idx_last =
364 (u8)(BIOS_GET_FIELD(clocks_table_entry.param0,
365 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM0_PROG_CLK_PROG_IDX_LAST));
366 clk_domain_data.v3x_prog.noise_unaware_ordering_index =
367 (u8)(BIOS_GET_FIELD(clocks_table_entry.param2,
368 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM2_PROG_NOISE_UNAWARE_ORDERING_IDX));
369
370 if (clk_domain_data.v3x.b_noise_aware_capable) {
371 clk_domain_data.v3x_prog.noise_aware_ordering_index =
372 (u8)(BIOS_GET_FIELD(clocks_table_entry.param2,
373 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM2_PROG_NOISE_AWARE_ORDERING_IDX));
374 clk_domain_data.v3x_prog.b_force_noise_unaware_ordering =
375 (u8)(BIOS_GET_FIELD(clocks_table_entry.param2,
376 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM2_PROG_FORCE_NOISE_UNAWARE_ORDERING));
377 } else {
378 clk_domain_data.v3x_prog.noise_aware_ordering_index =
379 CTRL_CLK_CLK_DOMAIN_3X_PROG_ORDERING_INDEX_INVALID;
380 clk_domain_data.v3x_prog.b_force_noise_unaware_ordering = false;
381 }
382 clk_domain_data.v3x_prog.factory_offset_khz = 0;
383 clk_domain_data.v3x_prog.freq_delta_min_mhz = 0;
384 clk_domain_data.v3x_prog.freq_delta_max_mhz = 0;
385 clk_domain_data.v3x_slave.master_idx =
386 (u8)(BIOS_GET_FIELD(clocks_table_entry.param1,
387 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM1_SLAVE_MASTER_DOMAIN));
388 break;
389
390 default:
391 nvgpu_err(g,
392 "error reading clock domain entry %d", index);
393 status = -EINVAL;
394 goto done;
395
396 }
397 pclkdomain_dev = construct_clk_domain(g,
398 (void *)&clk_domain_data);
399 if (pclkdomain_dev == NULL) {
400 nvgpu_err(g,
401 "unable to construct clock domain boardobj for %d",
402 index);
403 status = -EINVAL;
404 goto done;
405 }
406 status = boardobjgrp_objinsert(&pclkdomainobjs->super.super,
407 (struct boardobj *)pclkdomain_dev, index);
408 if (status) {
409 nvgpu_err(g,
410 "unable to insert clock domain boardobj for %d", index);
411 status = -EINVAL;
412 goto done;
413 }
414 clocks_tbl_entry_ptr += clocks_table_header.entry_size;
415 }
416
417done:
418 gk20a_dbg_info(" done status %x", status);
419 return status;
420}
421
422static u32 clkdomainclkproglink_not_supported(struct gk20a *g,
423 struct clk_pmupstate *pclk,
424 struct clk_domain *pdomain)
425{
426 gk20a_dbg_info("");
427 return -EINVAL;
428}
429
430static int clkdomainvfsearch_stub(
431 struct gk20a *g,
432 struct clk_pmupstate *pclk,
433 struct clk_domain *pdomain,
434 u16 *clkmhz,
435 u32 *voltuv,
436 u8 rail)
437
438{
439 gk20a_dbg_info("");
440 return -EINVAL;
441}
442
443static u32 clkdomaingetfpoints_stub(
444 struct gk20a *g,
445 struct clk_pmupstate *pclk,
446 struct clk_domain *pdomain,
447 u32 *pfpointscount,
448 u16 *pfreqpointsinmhz,
449 u8 rail)
450{
451 gk20a_dbg_info("");
452 return -EINVAL;
453}
454
455
456static u32 clk_domain_construct_super(struct gk20a *g,
457 struct boardobj **ppboardobj,
458 u16 size, void *pargs)
459{
460 struct clk_domain *pdomain;
461 struct clk_domain *ptmpdomain = (struct clk_domain *)pargs;
462 u32 status = 0;
463
464 status = boardobj_construct_super(g, ppboardobj,
465 size, pargs);
466
467 if (status)
468 return -EINVAL;
469
470 pdomain = (struct clk_domain *)*ppboardobj;
471
472 pdomain->super.pmudatainit =
473 clk_domain_pmudatainit_super;
474
475 pdomain->clkdomainclkproglink =
476 clkdomainclkproglink_not_supported;
477
478 pdomain->clkdomainclkvfsearch =
479 clkdomainvfsearch_stub;
480
481 pdomain->clkdomainclkgetfpoints =
482 clkdomaingetfpoints_stub;
483
484 pdomain->api_domain = ptmpdomain->api_domain;
485 pdomain->domain = ptmpdomain->domain;
486 pdomain->perf_domain_grp_idx =
487 ptmpdomain->perf_domain_grp_idx;
488
489 return status;
490}
491
492static u32 _clk_domain_pmudatainit_3x(struct gk20a *g,
493 struct boardobj *board_obj_ptr,
494 struct nv_pmu_boardobj *ppmudata)
495{
496 u32 status = 0;
497 struct clk_domain_3x *pclk_domain_3x;
498 struct nv_pmu_clk_clk_domain_3x_boardobj_set *pset;
499
500 gk20a_dbg_info("");
501
502 status = clk_domain_pmudatainit_super(g, board_obj_ptr, ppmudata);
503 if (status != 0)
504 return status;
505
506 pclk_domain_3x = (struct clk_domain_3x *)board_obj_ptr;
507
508 pset = (struct nv_pmu_clk_clk_domain_3x_boardobj_set *)ppmudata;
509
510 pset->b_noise_aware_capable = pclk_domain_3x->b_noise_aware_capable;
511
512 return status;
513}
514
515static u32 clk_domain_construct_3x(struct gk20a *g,
516 struct boardobj **ppboardobj,
517 u16 size, void *pargs)
518{
519 struct boardobj *ptmpobj = (struct boardobj *)pargs;
520 struct clk_domain_3x *pdomain;
521 struct clk_domain_3x *ptmpdomain =
522 (struct clk_domain_3x *)pargs;
523 u32 status = 0;
524
525 ptmpobj->type_mask = BIT(CTRL_CLK_CLK_DOMAIN_TYPE_3X);
526 status = clk_domain_construct_super(g, ppboardobj,
527 size, pargs);
528 if (status)
529 return -EINVAL;
530
531 pdomain = (struct clk_domain_3x *)*ppboardobj;
532
533 pdomain->super.super.pmudatainit =
534 _clk_domain_pmudatainit_3x;
535
536 pdomain->b_noise_aware_capable = ptmpdomain->b_noise_aware_capable;
537
538 return status;
539}
540
541static u32 clkdomainclkproglink_3x_prog(struct gk20a *g,
542 struct clk_pmupstate *pclk,
543 struct clk_domain *pdomain)
544{
545 u32 status = 0;
546 struct clk_domain_3x_prog *p3xprog =
547 (struct clk_domain_3x_prog *)pdomain;
548 struct clk_prog *pprog = NULL;
549 u8 i;
550
551 gk20a_dbg_info("");
552
553 for (i = p3xprog->clk_prog_idx_first;
554 i <= p3xprog->clk_prog_idx_last;
555 i++) {
556 pprog = CLK_CLK_PROG_GET(pclk, i);
557 if (pprog == NULL)
558 status = -EINVAL;
559 }
560 return status;
561}
562
563static int clkdomaingetslaveclk(struct gk20a *g,
564 struct clk_pmupstate *pclk,
565 struct clk_domain *pdomain,
566 u16 *pclkmhz,
567 u16 masterclkmhz)
568{
569 int status = 0;
570 struct clk_prog *pprog = NULL;
571 struct clk_prog_1x_master *pprog1xmaster = NULL;
572 u8 slaveidx;
573 struct clk_domain_3x_master *p3xmaster;
574
575 gk20a_dbg_info("");
576
577 if (pclkmhz == NULL)
578 return -EINVAL;
579
580 if (masterclkmhz == 0)
581 return -EINVAL;
582
583 slaveidx = BOARDOBJ_GET_IDX(pdomain);
584 p3xmaster = (struct clk_domain_3x_master *)
585 CLK_CLK_DOMAIN_GET(pclk,
586 ((struct clk_domain_3x_slave *)
587 pdomain)->master_idx);
588 pprog = CLK_CLK_PROG_GET(pclk, p3xmaster->super.clk_prog_idx_first);
589 pprog1xmaster = (struct clk_prog_1x_master *)pprog;
590
591 status = pprog1xmaster->getslaveclk(g, pclk, pprog1xmaster,
592 slaveidx, pclkmhz, masterclkmhz);
593 return status;
594}
595
596static int clkdomainvfsearch(struct gk20a *g,
597 struct clk_pmupstate *pclk,
598 struct clk_domain *pdomain,
599 u16 *pclkmhz,
600 u32 *pvoltuv,
601 u8 rail)
602{
603 int status = 0;
604 struct clk_domain_3x_master *p3xmaster =
605 (struct clk_domain_3x_master *)pdomain;
606 struct clk_prog *pprog = NULL;
607 struct clk_prog_1x_master *pprog1xmaster = NULL;
608 u8 i;
609 u8 *pslaveidx = NULL;
610 u8 slaveidx;
611 u16 clkmhz;
612 u32 voltuv;
613 u16 bestclkmhz;
614 u32 bestvoltuv;
615
616 gk20a_dbg_info("");
617
618 if ((pclkmhz == NULL) || (pvoltuv == NULL))
619 return -EINVAL;
620
621 if ((*pclkmhz != 0) && (*pvoltuv != 0))
622 return -EINVAL;
623
624 bestclkmhz = *pclkmhz;
625 bestvoltuv = *pvoltuv;
626
627 if (pdomain->super.implements(g, &pdomain->super,
628 CTRL_CLK_CLK_DOMAIN_TYPE_3X_SLAVE)) {
629 slaveidx = BOARDOBJ_GET_IDX(pdomain);
630 pslaveidx = &slaveidx;
631 p3xmaster = (struct clk_domain_3x_master *)
632 CLK_CLK_DOMAIN_GET(pclk,
633 ((struct clk_domain_3x_slave *)
634 pdomain)->master_idx);
635 }
636 /* Iterate over the set of CLK_PROGs pointed at by this domain.*/
637 for (i = p3xmaster->super.clk_prog_idx_first;
638 i <= p3xmaster->super.clk_prog_idx_last;
639 i++) {
640 clkmhz = *pclkmhz;
641 voltuv = *pvoltuv;
642 pprog = CLK_CLK_PROG_GET(pclk, i);
643
644 /* MASTER CLK_DOMAINs must point to MASTER CLK_PROGs.*/
645 if (!pprog->super.implements(g, &pprog->super,
646 CTRL_CLK_CLK_PROG_TYPE_1X_MASTER)) {
647 status = -EINVAL;
648 goto done;
649 }
650
651 pprog1xmaster = (struct clk_prog_1x_master *)pprog;
652 status = pprog1xmaster->vflookup(g, pclk, pprog1xmaster,
653 pslaveidx, &clkmhz, &voltuv, rail);
654 /* if look up has found the V or F value matching to other
655 exit */
656 if (status == 0) {
657 if (*pclkmhz == 0) {
658 bestclkmhz = clkmhz;
659 } else {
660 bestvoltuv = voltuv;
661 break;
662 }
663 }
664 }
665 /* clk and volt sent as zero to print vf table */
666 if ((*pclkmhz == 0) && (*pvoltuv == 0)) {
667 status = 0;
668 goto done;
669 }
670 /* atleast one search found a matching value? */
671 if ((bestvoltuv != 0) && (bestclkmhz != 0)) {
672 *pclkmhz = bestclkmhz;
673 *pvoltuv = bestvoltuv;
674 status = 0;
675 goto done;
676 }
677done:
678 gk20a_dbg_info("done status %x", status);
679 return status;
680}
681
682static u32 clkdomaingetfpoints
683(
684 struct gk20a *g,
685 struct clk_pmupstate *pclk,
686 struct clk_domain *pdomain,
687 u32 *pfpointscount,
688 u16 *pfreqpointsinmhz,
689 u8 rail
690)
691{
692 u32 status = 0;
693 struct clk_domain_3x_master *p3xmaster =
694 (struct clk_domain_3x_master *)pdomain;
695 struct clk_prog *pprog = NULL;
696 struct clk_prog_1x_master *pprog1xmaster = NULL;
697 u32 fpointscount = 0;
698 u32 remainingcount;
699 u32 totalcount;
700 u16 *freqpointsdata;
701 u8 i;
702
703 gk20a_dbg_info("");
704
705 if (pfpointscount == NULL)
706 return -EINVAL;
707
708 if ((pfreqpointsinmhz == NULL) && (*pfpointscount != 0))
709 return -EINVAL;
710
711 if (pdomain->super.implements(g, &pdomain->super,
712 CTRL_CLK_CLK_DOMAIN_TYPE_3X_SLAVE))
713 return -EINVAL;
714
715 freqpointsdata = pfreqpointsinmhz;
716 totalcount = 0;
717 fpointscount = *pfpointscount;
718 remainingcount = fpointscount;
719 /* Iterate over the set of CLK_PROGs pointed at by this domain.*/
720 for (i = p3xmaster->super.clk_prog_idx_first;
721 i <= p3xmaster->super.clk_prog_idx_last;
722 i++) {
723 pprog = CLK_CLK_PROG_GET(pclk, i);
724 pprog1xmaster = (struct clk_prog_1x_master *)pprog;
725 status = pprog1xmaster->getfpoints(g, pclk, pprog1xmaster,
726 &fpointscount, &freqpointsdata, rail);
727 if (status) {
728 *pfpointscount = 0;
729 goto done;
730 }
731 totalcount += fpointscount;
732 if (*pfpointscount) {
733 remainingcount -= fpointscount;
734 fpointscount = remainingcount;
735 } else
736 fpointscount = 0;
737
738 }
739
740 *pfpointscount = totalcount;
741done:
742 gk20a_dbg_info("done status %x", status);
743 return status;
744}
745
746static u32 _clk_domain_pmudatainit_3x_prog(struct gk20a *g,
747 struct boardobj *board_obj_ptr,
748 struct nv_pmu_boardobj *ppmudata)
749{
750 u32 status = 0;
751 struct clk_domain_3x_prog *pclk_domain_3x_prog;
752 struct nv_pmu_clk_clk_domain_3x_prog_boardobj_set *pset;
753 struct clk_domains *pdomains = &(g->clk_pmu.clk_domainobjs);
754
755 gk20a_dbg_info("");
756
757 status = _clk_domain_pmudatainit_3x(g, board_obj_ptr, ppmudata);
758 if (status != 0)
759 return status;
760
761 pclk_domain_3x_prog = (struct clk_domain_3x_prog *)board_obj_ptr;
762
763 pset = (struct nv_pmu_clk_clk_domain_3x_prog_boardobj_set *)
764 ppmudata;
765
766 pset->clk_prog_idx_first = pclk_domain_3x_prog->clk_prog_idx_first;
767 pset->clk_prog_idx_last = pclk_domain_3x_prog->clk_prog_idx_last;
768 pset->noise_unaware_ordering_index =
769 pclk_domain_3x_prog->noise_unaware_ordering_index;
770 pset->noise_aware_ordering_index =
771 pclk_domain_3x_prog->noise_aware_ordering_index;
772 pset->b_force_noise_unaware_ordering =
773 pclk_domain_3x_prog->b_force_noise_unaware_ordering;
774 pset->factory_offset_khz = pclk_domain_3x_prog->factory_offset_khz;
775 pset->freq_delta_min_mhz = pclk_domain_3x_prog->freq_delta_min_mhz;
776 pset->freq_delta_max_mhz = pclk_domain_3x_prog->freq_delta_max_mhz;
777 memcpy(&pset->deltas, &pdomains->deltas,
778 (sizeof(struct ctrl_clk_clk_delta)));
779
780 return status;
781}
782
783static u32 clk_domain_construct_3x_prog(struct gk20a *g,
784 struct boardobj **ppboardobj,
785 u16 size, void *pargs)
786{
787 struct boardobj *ptmpobj = (struct boardobj *)pargs;
788 struct clk_domain_3x_prog *pdomain;
789 struct clk_domain_3x_prog *ptmpdomain =
790 (struct clk_domain_3x_prog *)pargs;
791 u32 status = 0;
792
793 ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_DOMAIN_TYPE_3X_PROG);
794 status = clk_domain_construct_3x(g, ppboardobj, size, pargs);
795 if (status)
796 return -EINVAL;
797
798 pdomain = (struct clk_domain_3x_prog *)*ppboardobj;
799
800 pdomain->super.super.super.pmudatainit =
801 _clk_domain_pmudatainit_3x_prog;
802
803 pdomain->super.super.clkdomainclkproglink =
804 clkdomainclkproglink_3x_prog;
805
806 pdomain->super.super.clkdomainclkvfsearch =
807 clkdomainvfsearch;
808
809 pdomain->super.super.clkdomainclkgetfpoints =
810 clkdomaingetfpoints;
811
812 pdomain->clk_prog_idx_first = ptmpdomain->clk_prog_idx_first;
813 pdomain->clk_prog_idx_last = ptmpdomain->clk_prog_idx_last;
814 pdomain->noise_unaware_ordering_index =
815 ptmpdomain->noise_unaware_ordering_index;
816 pdomain->noise_aware_ordering_index =
817 ptmpdomain->noise_aware_ordering_index;
818 pdomain->b_force_noise_unaware_ordering =
819 ptmpdomain->b_force_noise_unaware_ordering;
820 pdomain->factory_offset_khz = ptmpdomain->factory_offset_khz;
821 pdomain->freq_delta_min_mhz = ptmpdomain->freq_delta_min_mhz;
822 pdomain->freq_delta_max_mhz = ptmpdomain->freq_delta_max_mhz;
823
824 return status;
825}
826
827static u32 _clk_domain_pmudatainit_3x_slave(struct gk20a *g,
828 struct boardobj *board_obj_ptr,
829 struct nv_pmu_boardobj *ppmudata)
830{
831 u32 status = 0;
832 struct clk_domain_3x_slave *pclk_domain_3x_slave;
833 struct nv_pmu_clk_clk_domain_3x_slave_boardobj_set *pset;
834
835 gk20a_dbg_info("");
836
837 status = _clk_domain_pmudatainit_3x_prog(g, board_obj_ptr, ppmudata);
838 if (status != 0)
839 return status;
840
841 pclk_domain_3x_slave = (struct clk_domain_3x_slave *)board_obj_ptr;
842
843 pset = (struct nv_pmu_clk_clk_domain_3x_slave_boardobj_set *)
844 ppmudata;
845
846 pset->master_idx = pclk_domain_3x_slave->master_idx;
847
848 return status;
849}
850
851static u32 clk_domain_construct_3x_slave(struct gk20a *g,
852 struct boardobj **ppboardobj,
853 u16 size, void *pargs)
854{
855 struct boardobj *ptmpobj = (struct boardobj *)pargs;
856 struct clk_domain_3x_slave *pdomain;
857 struct clk_domain_3x_slave *ptmpdomain =
858 (struct clk_domain_3x_slave *)pargs;
859 u32 status = 0;
860
861 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_CLK_CLK_DOMAIN_TYPE_3X_SLAVE)
862 return -EINVAL;
863
864 ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_DOMAIN_TYPE_3X_SLAVE);
865 status = clk_domain_construct_3x_prog(g, ppboardobj, size, pargs);
866 if (status)
867 return -EINVAL;
868
869 pdomain = (struct clk_domain_3x_slave *)*ppboardobj;
870
871 pdomain->super.super.super.super.pmudatainit =
872 _clk_domain_pmudatainit_3x_slave;
873
874 pdomain->master_idx = ptmpdomain->master_idx;
875
876 pdomain->clkdomainclkgetslaveclk =
877 clkdomaingetslaveclk;
878
879 return status;
880}
881
882static u32 clkdomainclkproglink_3x_master(struct gk20a *g,
883 struct clk_pmupstate *pclk,
884 struct clk_domain *pdomain)
885{
886 u32 status = 0;
887 struct clk_domain_3x_master *p3xmaster =
888 (struct clk_domain_3x_master *)pdomain;
889 struct clk_prog *pprog = NULL;
890 struct clk_prog_1x_master *pprog1xmaster = NULL;
891 u16 freq_max_last_mhz = 0;
892 u8 i;
893
894 gk20a_dbg_info("");
895
896 status = clkdomainclkproglink_3x_prog(g, pclk, pdomain);
897 if (status)
898 goto done;
899
900 /* Iterate over the set of CLK_PROGs pointed at by this domain.*/
901 for (i = p3xmaster->super.clk_prog_idx_first;
902 i <= p3xmaster->super.clk_prog_idx_last;
903 i++) {
904 pprog = CLK_CLK_PROG_GET(pclk, i);
905
906 /* MASTER CLK_DOMAINs must point to MASTER CLK_PROGs.*/
907 if (!pprog->super.implements(g, &pprog->super,
908 CTRL_CLK_CLK_PROG_TYPE_1X_MASTER)) {
909 status = -EINVAL;
910 goto done;
911 }
912
913 pprog1xmaster = (struct clk_prog_1x_master *)pprog;
914 status = pprog1xmaster->vfflatten(g, pclk, pprog1xmaster,
915 BOARDOBJ_GET_IDX(p3xmaster), &freq_max_last_mhz);
916 if (status)
917 goto done;
918 }
919done:
920 gk20a_dbg_info("done status %x", status);
921 return status;
922}
923
924static u32 _clk_domain_pmudatainit_3x_master(struct gk20a *g,
925 struct boardobj *board_obj_ptr,
926 struct nv_pmu_boardobj *ppmudata)
927{
928 u32 status = 0;
929 struct clk_domain_3x_master *pclk_domain_3x_master;
930 struct nv_pmu_clk_clk_domain_3x_master_boardobj_set *pset;
931
932 gk20a_dbg_info("");
933
934 status = _clk_domain_pmudatainit_3x_prog(g, board_obj_ptr, ppmudata);
935 if (status != 0)
936 return status;
937
938 pclk_domain_3x_master = (struct clk_domain_3x_master *)board_obj_ptr;
939
940 pset = (struct nv_pmu_clk_clk_domain_3x_master_boardobj_set *)
941 ppmudata;
942
943 pset->slave_idxs_mask = pclk_domain_3x_master->slave_idxs_mask;
944
945 return status;
946}
947
948static u32 clk_domain_construct_3x_master(struct gk20a *g,
949 struct boardobj **ppboardobj,
950 u16 size, void *pargs)
951{
952 struct boardobj *ptmpobj = (struct boardobj *)pargs;
953 struct clk_domain_3x_master *pdomain;
954 u32 status = 0;
955
956 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_CLK_CLK_DOMAIN_TYPE_3X_MASTER)
957 return -EINVAL;
958
959 ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_DOMAIN_TYPE_3X_MASTER);
960 status = clk_domain_construct_3x_prog(g, ppboardobj, size, pargs);
961 if (status)
962 return -EINVAL;
963
964 pdomain = (struct clk_domain_3x_master *)*ppboardobj;
965
966 pdomain->super.super.super.super.pmudatainit =
967 _clk_domain_pmudatainit_3x_master;
968 pdomain->super.super.super.clkdomainclkproglink =
969 clkdomainclkproglink_3x_master;
970
971 pdomain->slave_idxs_mask = 0;
972
973 return status;
974}
975
976static u32 clkdomainclkproglink_fixed(struct gk20a *g,
977 struct clk_pmupstate *pclk,
978 struct clk_domain *pdomain)
979{
980 gk20a_dbg_info("");
981 return 0;
982}
983
984static u32 _clk_domain_pmudatainit_3x_fixed(struct gk20a *g,
985 struct boardobj *board_obj_ptr,
986 struct nv_pmu_boardobj *ppmudata)
987{
988 u32 status = 0;
989 struct clk_domain_3x_fixed *pclk_domain_3x_fixed;
990 struct nv_pmu_clk_clk_domain_3x_fixed_boardobj_set *pset;
991
992 gk20a_dbg_info("");
993
994 status = _clk_domain_pmudatainit_3x(g, board_obj_ptr, ppmudata);
995 if (status != 0)
996 return status;
997
998 pclk_domain_3x_fixed = (struct clk_domain_3x_fixed *)board_obj_ptr;
999
1000 pset = (struct nv_pmu_clk_clk_domain_3x_fixed_boardobj_set *)
1001 ppmudata;
1002
1003 pset->freq_mhz = pclk_domain_3x_fixed->freq_mhz;
1004
1005 return status;
1006}
1007
1008static u32 clk_domain_construct_3x_fixed(struct gk20a *g,
1009 struct boardobj **ppboardobj,
1010 u16 size, void *pargs)
1011{
1012 struct boardobj *ptmpobj = (struct boardobj *)pargs;
1013 struct clk_domain_3x_fixed *pdomain;
1014 struct clk_domain_3x_fixed *ptmpdomain =
1015 (struct clk_domain_3x_fixed *)pargs;
1016 u32 status = 0;
1017
1018 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_CLK_CLK_DOMAIN_TYPE_3X_FIXED)
1019 return -EINVAL;
1020
1021 ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_DOMAIN_TYPE_3X_FIXED);
1022 status = clk_domain_construct_3x(g, ppboardobj, size, pargs);
1023 if (status)
1024 return -EINVAL;
1025
1026 pdomain = (struct clk_domain_3x_fixed *)*ppboardobj;
1027
1028 pdomain->super.super.super.pmudatainit =
1029 _clk_domain_pmudatainit_3x_fixed;
1030
1031 pdomain->super.super.clkdomainclkproglink =
1032 clkdomainclkproglink_fixed;
1033
1034 pdomain->freq_mhz = ptmpdomain->freq_mhz;
1035
1036 return status;
1037}
1038
1039static struct clk_domain *construct_clk_domain(struct gk20a *g, void *pargs)
1040{
1041 struct boardobj *board_obj_ptr = NULL;
1042 u32 status;
1043
1044 gk20a_dbg_info(" %d", BOARDOBJ_GET_TYPE(pargs));
1045 switch (BOARDOBJ_GET_TYPE(pargs)) {
1046 case CTRL_CLK_CLK_DOMAIN_TYPE_3X_FIXED:
1047 status = clk_domain_construct_3x_fixed(g, &board_obj_ptr,
1048 sizeof(struct clk_domain_3x_fixed), pargs);
1049 break;
1050
1051 case CTRL_CLK_CLK_DOMAIN_TYPE_3X_MASTER:
1052 status = clk_domain_construct_3x_master(g, &board_obj_ptr,
1053 sizeof(struct clk_domain_3x_master), pargs);
1054 break;
1055
1056 case CTRL_CLK_CLK_DOMAIN_TYPE_3X_SLAVE:
1057 status = clk_domain_construct_3x_slave(g, &board_obj_ptr,
1058 sizeof(struct clk_domain_3x_slave), pargs);
1059 break;
1060
1061 default:
1062 return NULL;
1063 }
1064
1065 if (status)
1066 return NULL;
1067
1068 gk20a_dbg_info(" Done");
1069
1070 return (struct clk_domain *)board_obj_ptr;
1071}
1072
1073static u32 clk_domain_pmudatainit_super(struct gk20a *g,
1074 struct boardobj *board_obj_ptr,
1075 struct nv_pmu_boardobj *ppmudata)
1076{
1077 u32 status = 0;
1078 struct clk_domain *pclk_domain;
1079 struct nv_pmu_clk_clk_domain_boardobj_set *pset;
1080
1081 gk20a_dbg_info("");
1082
1083 status = boardobj_pmudatainit_super(g, board_obj_ptr, ppmudata);
1084 if (status != 0)
1085 return status;
1086
1087 pclk_domain = (struct clk_domain *)board_obj_ptr;
1088
1089 pset = (struct nv_pmu_clk_clk_domain_boardobj_set *)ppmudata;
1090
1091 pset->domain = pclk_domain->domain;
1092 pset->api_domain = pclk_domain->api_domain;
1093 pset->perf_domain_grp_idx = pclk_domain->perf_domain_grp_idx;
1094
1095 return status;
1096}
1097
1098u32 clk_domain_clk_prog_link(struct gk20a *g, struct clk_pmupstate *pclk)
1099{
1100 u32 status = 0;
1101 struct clk_domain *pdomain;
1102 u8 i;
1103
1104 /* Iterate over all CLK_DOMAINs and flatten their VF curves.*/
1105 BOARDOBJGRP_FOR_EACH(&(pclk->clk_domainobjs.super.super),
1106 struct clk_domain *, pdomain, i) {
1107 status = pdomain->clkdomainclkproglink(g, pclk, pdomain);
1108 if (status) {
1109 nvgpu_err(g,
1110 "error flattening VF for CLK DOMAIN - 0x%x",
1111 pdomain->domain);
1112 goto done;
1113 }
1114 }
1115
1116done:
1117 return status;
1118}