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