summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/clk
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/nvgpu/clk')
-rw-r--r--drivers/gpu/nvgpu/clk/clk.c575
-rw-r--r--drivers/gpu/nvgpu/clk/clk.h130
-rw-r--r--drivers/gpu/nvgpu/clk/clk_domain.c1118
-rw-r--r--drivers/gpu/nvgpu/clk/clk_domain.h125
-rw-r--r--drivers/gpu/nvgpu/clk/clk_fll.c444
-rw-r--r--drivers/gpu/nvgpu/clk/clk_fll.h77
-rw-r--r--drivers/gpu/nvgpu/clk/clk_freq_controller.c455
-rw-r--r--drivers/gpu/nvgpu/clk/clk_freq_controller.h84
-rw-r--r--drivers/gpu/nvgpu/clk/clk_mclk.h60
-rw-r--r--drivers/gpu/nvgpu/clk/clk_prog.c1109
-rw-r--r--drivers/gpu/nvgpu/clk/clk_prog.h100
-rw-r--r--drivers/gpu/nvgpu/clk/clk_vf_point.c421
-rw-r--r--drivers/gpu/nvgpu/clk/clk_vf_point.h83
-rw-r--r--drivers/gpu/nvgpu/clk/clk_vin.c480
-rw-r--r--drivers/gpu/nvgpu/clk/clk_vin.h65
15 files changed, 5326 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/clk/clk.c b/drivers/gpu/nvgpu/clk/clk.c
new file mode 100644
index 00000000..3906be48
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk.c
@@ -0,0 +1,575 @@
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/pmu.h>
24#include <nvgpu/pmuif/nvgpu_gpmu_cmdif.h>
25
26#include "gk20a/gk20a.h"
27#include "clk.h"
28#include "ctrl/ctrlclk.h"
29#include "ctrl/ctrlvolt.h"
30#include "volt/volt.h"
31
32#define BOOT_GPC2CLK_MHZ 2581
33#define BOOT_MCLK_MHZ 3003
34
35struct clkrpc_pmucmdhandler_params {
36 struct nv_pmu_clk_rpc *prpccall;
37 u32 success;
38};
39
40static void clkrpc_pmucmdhandler(struct gk20a *g, struct pmu_msg *msg,
41 void *param, u32 handle, u32 status)
42{
43 struct clkrpc_pmucmdhandler_params *phandlerparams =
44 (struct clkrpc_pmucmdhandler_params *)param;
45
46 gk20a_dbg_info("");
47
48 if (msg->msg.clk.msg_type != NV_PMU_CLK_MSG_ID_RPC) {
49 nvgpu_err(g, "unsupported msg for VFE LOAD RPC %x",
50 msg->msg.clk.msg_type);
51 return;
52 }
53
54 if (phandlerparams->prpccall->b_supported)
55 phandlerparams->success = 1;
56}
57
58int clk_pmu_freq_controller_load(struct gk20a *g, bool bload, u8 bit_idx)
59{
60 struct pmu_cmd cmd;
61 struct pmu_msg msg;
62 struct pmu_payload payload;
63 u32 status;
64 u32 seqdesc;
65 struct nv_pmu_clk_rpc rpccall;
66 struct clkrpc_pmucmdhandler_params handler;
67 struct nv_pmu_clk_load *clkload;
68 struct clk_freq_controllers *pclk_freq_controllers;
69 struct ctrl_boardobjgrp_mask_e32 *load_mask;
70 struct boardobjgrpmask_e32 isolate_cfc_mask;
71
72 memset(&payload, 0, sizeof(struct pmu_payload));
73 memset(&rpccall, 0, sizeof(struct nv_pmu_clk_rpc));
74 memset(&handler, 0, sizeof(struct clkrpc_pmucmdhandler_params));
75
76 pclk_freq_controllers = &g->clk_pmu.clk_freq_controllers;
77 rpccall.function = NV_PMU_CLK_RPC_ID_LOAD;
78 clkload = &rpccall.params.clk_load;
79 clkload->feature = NV_NV_PMU_CLK_LOAD_FEATURE_FREQ_CONTROLLER;
80 clkload->action_mask = bload ?
81 NV_NV_PMU_CLK_LOAD_ACTION_MASK_FREQ_CONTROLLER_CALLBACK_YES :
82 NV_NV_PMU_CLK_LOAD_ACTION_MASK_FREQ_CONTROLLER_CALLBACK_NO;
83
84 load_mask = &rpccall.params.clk_load.payload.freq_controllers.load_mask;
85
86 status = boardobjgrpmask_e32_init(&isolate_cfc_mask, NULL);
87
88 if (bit_idx == CTRL_CLK_CLK_FREQ_CONTROLLER_ID_ALL) {
89 status = boardobjgrpmask_export(
90 &pclk_freq_controllers->
91 freq_ctrl_load_mask.super,
92 pclk_freq_controllers->
93 freq_ctrl_load_mask.super.bitcount,
94 &load_mask->super);
95
96
97 } else {
98 status = boardobjgrpmask_bitset(&isolate_cfc_mask.super,
99 bit_idx);
100 status = boardobjgrpmask_export(&isolate_cfc_mask.super,
101 isolate_cfc_mask.super.bitcount,
102 &load_mask->super);
103 if (bload)
104 status = boardobjgrpmask_bitset(
105 &pclk_freq_controllers->
106 freq_ctrl_load_mask.super,
107 bit_idx);
108 else
109 status = boardobjgrpmask_bitclr(
110 &pclk_freq_controllers->
111 freq_ctrl_load_mask.super,
112 bit_idx);
113 }
114
115 if (status) {
116 nvgpu_err(g, "Error in generating mask used to select CFC");
117 goto done;
118 }
119
120 cmd.hdr.unit_id = PMU_UNIT_CLK;
121 cmd.hdr.size = (u32)sizeof(struct nv_pmu_clk_cmd) +
122 (u32)sizeof(struct pmu_hdr);
123
124 cmd.cmd.clk.cmd_type = NV_PMU_CLK_CMD_ID_RPC;
125 msg.hdr.size = sizeof(struct pmu_msg);
126
127 payload.in.buf = (u8 *)&rpccall;
128 payload.in.size = (u32)sizeof(struct nv_pmu_clk_rpc);
129 payload.in.fb_size = PMU_CMD_SUBMIT_PAYLOAD_PARAMS_FB_SIZE_UNUSED;
130 payload.in.offset = NV_PMU_CLK_CMD_RPC_ALLOC_OFFSET;
131
132 payload.out.buf = (u8 *)&rpccall;
133 payload.out.size = (u32)sizeof(struct nv_pmu_clk_rpc);
134 payload.out.fb_size = PMU_CMD_SUBMIT_PAYLOAD_PARAMS_FB_SIZE_UNUSED;
135 payload.out.offset = NV_PMU_CLK_MSG_RPC_ALLOC_OFFSET;
136
137 handler.prpccall = &rpccall;
138 handler.success = 0;
139 status = nvgpu_pmu_cmd_post(g, &cmd, NULL, &payload,
140 PMU_COMMAND_QUEUE_LPQ,
141 clkrpc_pmucmdhandler, (void *)&handler,
142 &seqdesc, ~0);
143
144 if (status) {
145 nvgpu_err(g, "unable to post clk RPC cmd %x",
146 cmd.cmd.clk.cmd_type);
147 goto done;
148 }
149
150 pmu_wait_message_cond(&g->pmu,
151 gk20a_get_gr_idle_timeout(g),
152 &handler.success, 1);
153
154 if (handler.success == 0) {
155 nvgpu_err(g, "rpc call to load freq cntlr cal failed");
156 status = -EINVAL;
157 }
158
159done:
160 return status;
161}
162
163u32 clk_pmu_vin_load(struct gk20a *g)
164{
165 struct pmu_cmd cmd;
166 struct pmu_msg msg;
167 struct pmu_payload payload;
168 u32 status;
169 u32 seqdesc;
170 struct nv_pmu_clk_rpc rpccall;
171 struct clkrpc_pmucmdhandler_params handler;
172 struct nv_pmu_clk_load *clkload;
173
174 memset(&payload, 0, sizeof(struct pmu_payload));
175 memset(&rpccall, 0, sizeof(struct nv_pmu_clk_rpc));
176 memset(&handler, 0, sizeof(struct clkrpc_pmucmdhandler_params));
177
178 rpccall.function = NV_PMU_CLK_RPC_ID_LOAD;
179 clkload = &rpccall.params.clk_load;
180 clkload->feature = NV_NV_PMU_CLK_LOAD_FEATURE_VIN;
181 clkload->action_mask = NV_NV_PMU_CLK_LOAD_ACTION_MASK_VIN_HW_CAL_PROGRAM_YES << 4;
182
183 cmd.hdr.unit_id = PMU_UNIT_CLK;
184 cmd.hdr.size = (u32)sizeof(struct nv_pmu_clk_cmd) +
185 (u32)sizeof(struct pmu_hdr);
186
187 cmd.cmd.clk.cmd_type = NV_PMU_CLK_CMD_ID_RPC;
188 msg.hdr.size = sizeof(struct pmu_msg);
189
190 payload.in.buf = (u8 *)&rpccall;
191 payload.in.size = (u32)sizeof(struct nv_pmu_clk_rpc);
192 payload.in.fb_size = PMU_CMD_SUBMIT_PAYLOAD_PARAMS_FB_SIZE_UNUSED;
193 payload.in.offset = NV_PMU_CLK_CMD_RPC_ALLOC_OFFSET;
194
195 payload.out.buf = (u8 *)&rpccall;
196 payload.out.size = (u32)sizeof(struct nv_pmu_clk_rpc);
197 payload.out.fb_size = PMU_CMD_SUBMIT_PAYLOAD_PARAMS_FB_SIZE_UNUSED;
198 payload.out.offset = NV_PMU_CLK_MSG_RPC_ALLOC_OFFSET;
199
200 handler.prpccall = &rpccall;
201 handler.success = 0;
202 status = nvgpu_pmu_cmd_post(g, &cmd, NULL, &payload,
203 PMU_COMMAND_QUEUE_LPQ,
204 clkrpc_pmucmdhandler, (void *)&handler,
205 &seqdesc, ~0);
206
207 if (status) {
208 nvgpu_err(g, "unable to post clk RPC cmd %x",
209 cmd.cmd.clk.cmd_type);
210 goto done;
211 }
212
213 pmu_wait_message_cond(&g->pmu,
214 gk20a_get_gr_idle_timeout(g),
215 &handler.success, 1);
216
217 if (handler.success == 0) {
218 nvgpu_err(g, "rpc call to load vin cal failed");
219 status = -EINVAL;
220 }
221
222done:
223 return status;
224}
225
226static u32 clk_pmu_vf_inject(struct gk20a *g, struct set_fll_clk *setfllclk)
227{
228 struct pmu_cmd cmd;
229 struct pmu_msg msg;
230 struct pmu_payload payload;
231 u32 status;
232 u32 seqdesc;
233 struct nv_pmu_clk_rpc rpccall;
234 struct clkrpc_pmucmdhandler_params handler;
235 struct nv_pmu_clk_vf_change_inject *vfchange;
236
237 memset(&payload, 0, sizeof(struct pmu_payload));
238 memset(&rpccall, 0, sizeof(struct nv_pmu_clk_rpc));
239 memset(&handler, 0, sizeof(struct clkrpc_pmucmdhandler_params));
240
241 if ((setfllclk->gpc2clkmhz == 0) || (setfllclk->xbar2clkmhz == 0) ||
242 (setfllclk->sys2clkmhz == 0) || (setfllclk->voltuv == 0))
243 return -EINVAL;
244
245 if ((setfllclk->target_regime_id_gpc > CTRL_CLK_FLL_REGIME_ID_FR) ||
246 (setfllclk->target_regime_id_sys > CTRL_CLK_FLL_REGIME_ID_FR) ||
247 (setfllclk->target_regime_id_xbar > CTRL_CLK_FLL_REGIME_ID_FR))
248 return -EINVAL;
249
250 rpccall.function = NV_PMU_CLK_RPC_ID_CLK_VF_CHANGE_INJECT;
251 vfchange = &rpccall.params.clk_vf_change_inject;
252 vfchange->flags = 0;
253 vfchange->clk_list.num_domains = 3;
254 vfchange->clk_list.clk_domains[0].clk_domain = CTRL_CLK_DOMAIN_GPC2CLK;
255 vfchange->clk_list.clk_domains[0].clk_freq_khz =
256 setfllclk->gpc2clkmhz * 1000;
257 vfchange->clk_list.clk_domains[0].clk_flags = 0;
258 vfchange->clk_list.clk_domains[0].current_regime_id =
259 setfllclk->current_regime_id_gpc;
260 vfchange->clk_list.clk_domains[0].target_regime_id =
261 setfllclk->target_regime_id_gpc;
262 vfchange->clk_list.clk_domains[1].clk_domain = CTRL_CLK_DOMAIN_XBAR2CLK;
263 vfchange->clk_list.clk_domains[1].clk_freq_khz =
264 setfllclk->xbar2clkmhz * 1000;
265 vfchange->clk_list.clk_domains[1].clk_flags = 0;
266 vfchange->clk_list.clk_domains[1].current_regime_id =
267 setfllclk->current_regime_id_xbar;
268 vfchange->clk_list.clk_domains[1].target_regime_id =
269 setfllclk->target_regime_id_xbar;
270 vfchange->clk_list.clk_domains[2].clk_domain = CTRL_CLK_DOMAIN_SYS2CLK;
271 vfchange->clk_list.clk_domains[2].clk_freq_khz =
272 setfllclk->sys2clkmhz * 1000;
273 vfchange->clk_list.clk_domains[2].clk_flags = 0;
274 vfchange->clk_list.clk_domains[2].current_regime_id =
275 setfllclk->current_regime_id_sys;
276 vfchange->clk_list.clk_domains[2].target_regime_id =
277 setfllclk->target_regime_id_sys;
278 vfchange->volt_list.num_rails = 1;
279 vfchange->volt_list.rails[0].volt_domain = CTRL_VOLT_DOMAIN_LOGIC;
280 vfchange->volt_list.rails[0].voltage_uv = setfllclk->voltuv;
281 vfchange->volt_list.rails[0].voltage_min_noise_unaware_uv =
282 setfllclk->voltuv;
283
284 cmd.hdr.unit_id = PMU_UNIT_CLK;
285 cmd.hdr.size = (u32)sizeof(struct nv_pmu_clk_cmd) +
286 (u32)sizeof(struct pmu_hdr);
287
288 cmd.cmd.clk.cmd_type = NV_PMU_CLK_CMD_ID_RPC;
289 msg.hdr.size = sizeof(struct pmu_msg);
290
291 payload.in.buf = (u8 *)&rpccall;
292 payload.in.size = (u32)sizeof(struct nv_pmu_clk_rpc);
293 payload.in.fb_size = PMU_CMD_SUBMIT_PAYLOAD_PARAMS_FB_SIZE_UNUSED;
294 payload.in.offset = NV_PMU_CLK_CMD_RPC_ALLOC_OFFSET;
295
296 payload.out.buf = (u8 *)&rpccall;
297 payload.out.size = (u32)sizeof(struct nv_pmu_clk_rpc);
298 payload.out.fb_size = PMU_CMD_SUBMIT_PAYLOAD_PARAMS_FB_SIZE_UNUSED;
299 payload.out.offset = NV_PMU_CLK_MSG_RPC_ALLOC_OFFSET;
300
301 handler.prpccall = &rpccall;
302 handler.success = 0;
303
304 status = nvgpu_pmu_cmd_post(g, &cmd, NULL, &payload,
305 PMU_COMMAND_QUEUE_LPQ,
306 clkrpc_pmucmdhandler, (void *)&handler,
307 &seqdesc, ~0);
308
309 if (status) {
310 nvgpu_err(g, "unable to post clk RPC cmd %x",
311 cmd.cmd.clk.cmd_type);
312 goto done;
313 }
314
315 pmu_wait_message_cond(&g->pmu,
316 gk20a_get_gr_idle_timeout(g),
317 &handler.success, 1);
318
319 if (handler.success == 0) {
320 nvgpu_err(g, "rpc call to inject clock failed");
321 status = -EINVAL;
322 }
323done:
324 return status;
325}
326
327static u32 find_regime_id(struct gk20a *g, u32 domain, u16 clkmhz)
328{
329 struct fll_device *pflldev;
330 u8 j;
331 struct clk_pmupstate *pclk = &g->clk_pmu;
332
333 BOARDOBJGRP_FOR_EACH(&(pclk->avfs_fllobjs.super.super),
334 struct fll_device *, pflldev, j) {
335 if (pflldev->clk_domain == domain) {
336 if (pflldev->regime_desc.fixed_freq_regime_limit_mhz >=
337 clkmhz)
338 return CTRL_CLK_FLL_REGIME_ID_FFR;
339 else
340 return CTRL_CLK_FLL_REGIME_ID_FR;
341 }
342 }
343 return CTRL_CLK_FLL_REGIME_ID_INVALID;
344}
345
346static int set_regime_id(struct gk20a *g, u32 domain, u32 regimeid)
347{
348 struct fll_device *pflldev;
349 u8 j;
350 struct clk_pmupstate *pclk = &g->clk_pmu;
351
352 BOARDOBJGRP_FOR_EACH(&(pclk->avfs_fllobjs.super.super),
353 struct fll_device *, pflldev, j) {
354 if (pflldev->clk_domain == domain) {
355 pflldev->regime_desc.regime_id = regimeid;
356 return 0;
357 }
358 }
359 return -EINVAL;
360}
361
362static int get_regime_id(struct gk20a *g, u32 domain, u32 *regimeid)
363{
364 struct fll_device *pflldev;
365 u8 j;
366 struct clk_pmupstate *pclk = &g->clk_pmu;
367
368 BOARDOBJGRP_FOR_EACH(&(pclk->avfs_fllobjs.super.super),
369 struct fll_device *, pflldev, j) {
370 if (pflldev->clk_domain == domain) {
371 *regimeid = pflldev->regime_desc.regime_id;
372 return 0;
373 }
374 }
375 return -EINVAL;
376}
377
378int clk_set_fll_clks(struct gk20a *g, struct set_fll_clk *setfllclk)
379{
380 int status = -EINVAL;
381
382 /*set regime ids */
383 status = get_regime_id(g, CTRL_CLK_DOMAIN_GPC2CLK,
384 &setfllclk->current_regime_id_gpc);
385 if (status)
386 goto done;
387
388 setfllclk->target_regime_id_gpc = find_regime_id(g,
389 CTRL_CLK_DOMAIN_GPC2CLK, setfllclk->gpc2clkmhz);
390
391 status = get_regime_id(g, CTRL_CLK_DOMAIN_SYS2CLK,
392 &setfllclk->current_regime_id_sys);
393 if (status)
394 goto done;
395
396 setfllclk->target_regime_id_sys = find_regime_id(g,
397 CTRL_CLK_DOMAIN_SYS2CLK, setfllclk->sys2clkmhz);
398
399 status = get_regime_id(g, CTRL_CLK_DOMAIN_XBAR2CLK,
400 &setfllclk->current_regime_id_xbar);
401 if (status)
402 goto done;
403
404 setfllclk->target_regime_id_xbar = find_regime_id(g,
405 CTRL_CLK_DOMAIN_XBAR2CLK, setfllclk->xbar2clkmhz);
406
407 status = clk_pmu_vf_inject(g, setfllclk);
408
409 if (status)
410 nvgpu_err(g, "vf inject to change clk failed");
411
412 /* save regime ids */
413 status = set_regime_id(g, CTRL_CLK_DOMAIN_XBAR2CLK,
414 setfllclk->target_regime_id_xbar);
415 if (status)
416 goto done;
417
418 status = set_regime_id(g, CTRL_CLK_DOMAIN_GPC2CLK,
419 setfllclk->target_regime_id_gpc);
420 if (status)
421 goto done;
422
423 status = set_regime_id(g, CTRL_CLK_DOMAIN_SYS2CLK,
424 setfllclk->target_regime_id_sys);
425 if (status)
426 goto done;
427done:
428 return status;
429}
430
431int clk_get_fll_clks(struct gk20a *g, struct set_fll_clk *setfllclk)
432{
433 int status = -EINVAL;
434 struct clk_domain *pdomain;
435 u8 i;
436 struct clk_pmupstate *pclk = &g->clk_pmu;
437 u16 clkmhz = 0;
438 struct clk_domain_3x_master *p3xmaster;
439 struct clk_domain_3x_slave *p3xslave;
440 unsigned long slaveidxmask;
441
442 if (setfllclk->gpc2clkmhz == 0)
443 return -EINVAL;
444
445 BOARDOBJGRP_FOR_EACH(&(pclk->clk_domainobjs.super.super),
446 struct clk_domain *, pdomain, i) {
447
448 if (pdomain->api_domain == CTRL_CLK_DOMAIN_GPC2CLK) {
449
450 if (!pdomain->super.implements(g, &pdomain->super,
451 CTRL_CLK_CLK_DOMAIN_TYPE_3X_MASTER)) {
452 status = -EINVAL;
453 goto done;
454 }
455 p3xmaster = (struct clk_domain_3x_master *)pdomain;
456 slaveidxmask = p3xmaster->slave_idxs_mask;
457 for_each_set_bit(i, &slaveidxmask, 32) {
458 p3xslave = (struct clk_domain_3x_slave *)
459 CLK_CLK_DOMAIN_GET(pclk, i);
460 if ((p3xslave->super.super.super.api_domain !=
461 CTRL_CLK_DOMAIN_XBAR2CLK) &&
462 (p3xslave->super.super.super.api_domain !=
463 CTRL_CLK_DOMAIN_SYS2CLK))
464 continue;
465 clkmhz = 0;
466 status = p3xslave->clkdomainclkgetslaveclk(g,
467 pclk,
468 (struct clk_domain *)p3xslave,
469 &clkmhz,
470 setfllclk->gpc2clkmhz);
471 if (status) {
472 status = -EINVAL;
473 goto done;
474 }
475 if (p3xslave->super.super.super.api_domain ==
476 CTRL_CLK_DOMAIN_XBAR2CLK)
477 setfllclk->xbar2clkmhz = clkmhz;
478 if (p3xslave->super.super.super.api_domain ==
479 CTRL_CLK_DOMAIN_SYS2CLK)
480 setfllclk->sys2clkmhz = clkmhz;
481 }
482 }
483 }
484done:
485 return status;
486}
487
488u32 clk_domain_print_vf_table(struct gk20a *g, u32 clkapidomain)
489{
490 u32 status = -EINVAL;
491 struct clk_domain *pdomain;
492 u8 i;
493 struct clk_pmupstate *pclk = &g->clk_pmu;
494 u16 clkmhz = 0;
495 u32 volt = 0;
496
497 BOARDOBJGRP_FOR_EACH(&(pclk->clk_domainobjs.super.super),
498 struct clk_domain *, pdomain, i) {
499 if (pdomain->api_domain == clkapidomain) {
500 status = pdomain->clkdomainclkvfsearch(g, pclk,
501 pdomain, &clkmhz, &volt,
502 CLK_PROG_VFE_ENTRY_LOGIC);
503 status = pdomain->clkdomainclkvfsearch(g, pclk,
504 pdomain, &clkmhz, &volt,
505 CLK_PROG_VFE_ENTRY_SRAM);
506 }
507 }
508 return status;
509}
510
511u32 clk_domain_get_f_or_v(
512 struct gk20a *g,
513 u32 clkapidomain,
514 u16 *pclkmhz,
515 u32 *pvoltuv,
516 u8 railidx
517)
518{
519 u32 status = -EINVAL;
520 struct clk_domain *pdomain;
521 u8 i;
522 struct clk_pmupstate *pclk = &g->clk_pmu;
523 u8 rail;
524
525 if ((pclkmhz == NULL) || (pvoltuv == NULL))
526 return -EINVAL;
527
528 if (railidx == CTRL_VOLT_DOMAIN_LOGIC)
529 rail = CLK_PROG_VFE_ENTRY_LOGIC;
530 else if (railidx == CTRL_VOLT_DOMAIN_SRAM)
531 rail = CLK_PROG_VFE_ENTRY_SRAM;
532 else
533 return -EINVAL;
534
535 BOARDOBJGRP_FOR_EACH(&(pclk->clk_domainobjs.super.super),
536 struct clk_domain *, pdomain, i) {
537 if (pdomain->api_domain == clkapidomain) {
538 status = pdomain->clkdomainclkvfsearch(g, pclk,
539 pdomain, pclkmhz, pvoltuv, rail);
540 return status;
541 }
542 }
543 return status;
544}
545
546u32 clk_domain_get_f_points(
547 struct gk20a *g,
548 u32 clkapidomain,
549 u32 *pfpointscount,
550 u16 *pfreqpointsinmhz
551)
552{
553 u32 status = -EINVAL;
554 struct clk_domain *pdomain;
555 u8 i;
556 struct clk_pmupstate *pclk = &g->clk_pmu;
557
558 if (pfpointscount == NULL)
559 return -EINVAL;
560
561 if ((pfreqpointsinmhz == NULL) && (*pfpointscount != 0))
562 return -EINVAL;
563
564 BOARDOBJGRP_FOR_EACH(&(pclk->clk_domainobjs.super.super),
565 struct clk_domain *, pdomain, i) {
566 if (pdomain->api_domain == clkapidomain) {
567 status = pdomain->clkdomainclkgetfpoints(g, pclk,
568 pdomain, pfpointscount,
569 pfreqpointsinmhz,
570 CLK_PROG_VFE_ENTRY_LOGIC);
571 return status;
572 }
573 }
574 return status;
575}
diff --git a/drivers/gpu/nvgpu/clk/clk.h b/drivers/gpu/nvgpu/clk/clk.h
new file mode 100644
index 00000000..a19e2e77
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk.h
@@ -0,0 +1,130 @@
1/*
2 * general clock structures & definitions
3 *
4 * Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 */
24#ifndef _CLK_H_
25#define _CLK_H_
26
27#include "clk_vin.h"
28#include "clk_fll.h"
29#include "clk_domain.h"
30#include "clk_prog.h"
31#include "clk_vf_point.h"
32#include "clk_mclk.h"
33#include "clk_freq_controller.h"
34
35#define NV_PERF_DOMAIN_4X_CLOCK_DOMAIN_SKIP 0x10
36#define NV_PERF_DOMAIN_4X_CLOCK_DOMAIN_MASK 0x1F
37#define NV_PERF_DOMAIN_4X_CLOCK_DOMAIN_SHIFT 0
38
39struct gk20a;
40
41/* clock related defines for GPUs supporting clock control from pmu*/
42struct clk_pmupstate {
43 struct avfsvinobjs avfs_vinobjs;
44 struct avfsfllobjs avfs_fllobjs;
45 struct clk_domains clk_domainobjs;
46 struct clk_progs clk_progobjs;
47 struct clk_vf_points clk_vf_pointobjs;
48 struct clk_mclk_state clk_mclk;
49 struct clk_freq_controllers clk_freq_controllers;
50};
51
52struct clockentry {
53 u8 vbios_clk_domain;
54 u8 clk_which;
55 u8 perf_index;
56 u32 api_clk_domain;
57};
58
59struct set_fll_clk {
60 u32 voltuv;
61 u16 gpc2clkmhz;
62 u32 current_regime_id_gpc;
63 u32 target_regime_id_gpc;
64 u16 sys2clkmhz;
65 u32 current_regime_id_sys;
66 u32 target_regime_id_sys;
67 u16 xbar2clkmhz;
68 u32 current_regime_id_xbar;
69 u32 target_regime_id_xbar;
70};
71
72#define NV_PERF_HEADER_4X_CLOCKS_DOMAINS_MAX_NUMCLKS 9
73
74struct vbios_clock_domain {
75 u8 clock_type;
76 u8 num_domains;
77 struct clockentry clock_entry[NV_PERF_HEADER_4X_CLOCKS_DOMAINS_MAX_NUMCLKS];
78};
79
80struct vbios_clocks_table_1x_hal_clock_entry {
81 enum nv_pmu_clk_clkwhich domain;
82 bool b_noise_aware_capable;
83};
84
85#define NV_PERF_HEADER_4X_CLOCKS_DOMAINS_4_GPC2CLK 0
86#define NV_PERF_HEADER_4X_CLOCKS_DOMAINS_4_XBAR2CLK 1
87#define NV_PERF_HEADER_4X_CLOCKS_DOMAINS_4_DRAMCLK 2
88#define NV_PERF_HEADER_4X_CLOCKS_DOMAINS_4_SYS2CLK 3
89#define NV_PERF_HEADER_4X_CLOCKS_DOMAINS_4_HUB2CLK 4
90#define NV_PERF_HEADER_4X_CLOCKS_DOMAINS_4_MSDCLK 5
91#define NV_PERF_HEADER_4X_CLOCKS_DOMAINS_4_PWRCLK 6
92#define NV_PERF_HEADER_4X_CLOCKS_DOMAINS_4_DISPCLK 7
93#define NV_PERF_HEADER_4X_CLOCKS_DOMAINS_4_NUMCLKS 8
94
95#define PERF_CLK_MCLK 0
96#define PERF_CLK_DISPCLK 1
97#define PERF_CLK_GPC2CLK 2
98#define PERF_CLK_HOSTCLK 3
99#define PERF_CLK_LTC2CLK 4
100#define PERF_CLK_SYS2CLK 5
101#define PERF_CLK_HUB2CLK 6
102#define PERF_CLK_LEGCLK 7
103#define PERF_CLK_MSDCLK 8
104#define PERF_CLK_XCLK 9
105#define PERF_CLK_PWRCLK 10
106#define PERF_CLK_XBAR2CLK 11
107#define PERF_CLK_PCIEGENCLK 12
108#define PERF_CLK_NUM 13
109
110#define BOOT_GPC2CLK_MHZ 2581
111
112u32 clk_pmu_vin_load(struct gk20a *g);
113u32 clk_domain_print_vf_table(struct gk20a *g, u32 clkapidomain);
114u32 clk_domain_get_f_or_v(
115 struct gk20a *g,
116 u32 clkapidomain,
117 u16 *pclkmhz,
118 u32 *pvoltuv,
119 u8 railidx
120);
121u32 clk_domain_get_f_points(
122 struct gk20a *g,
123 u32 clkapidomain,
124 u32 *fpointscount,
125 u16 *freqpointsinmhz
126);
127int clk_get_fll_clks(struct gk20a *g, struct set_fll_clk *fllclk);
128int clk_set_fll_clks(struct gk20a *g, struct set_fll_clk *fllclk);
129int clk_pmu_freq_controller_load(struct gk20a *g, bool bload, u8 bit_idx);
130#endif
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}
diff --git a/drivers/gpu/nvgpu/clk/clk_domain.h b/drivers/gpu/nvgpu/clk/clk_domain.h
new file mode 100644
index 00000000..5374d643
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk_domain.h
@@ -0,0 +1,125 @@
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#ifndef _CLKDOMAIN_H_
24#define _CLKDOMAIN_H_
25
26#include "ctrl/ctrlclk.h"
27#include "ctrl/ctrlboardobj.h"
28#include <nvgpu/pmuif/nvgpu_gpmu_cmdif.h>
29#include "boardobj/boardobjgrp_e32.h"
30#include "boardobj/boardobjgrpmask.h"
31
32struct clk_domains;
33struct clk_domain;
34
35/*data and function definition to talk to driver*/
36u32 clk_domain_sw_setup(struct gk20a *g);
37u32 clk_domain_pmu_setup(struct gk20a *g);
38
39typedef u32 clkproglink(struct gk20a *g, struct clk_pmupstate *pclk,
40 struct clk_domain *pdomain);
41
42typedef int clkvfsearch(struct gk20a *g, struct clk_pmupstate *pclk,
43 struct clk_domain *pdomain, u16 *clkmhz,
44 u32 *voltuv, u8 rail);
45
46typedef int clkgetslaveclk(struct gk20a *g, struct clk_pmupstate *pclk,
47 struct clk_domain *pdomain, u16 *clkmhz,
48 u16 masterclkmhz);
49
50typedef u32 clkgetfpoints(struct gk20a *g, struct clk_pmupstate *pclk,
51 struct clk_domain *pdomain, u32 *pfpointscount,
52 u16 *pfreqpointsinmhz, u8 rail);
53
54struct clk_domains {
55 struct boardobjgrp_e32 super;
56 u8 n_num_entries;
57 u8 version;
58 bool b_enforce_vf_monotonicity;
59 bool b_enforce_vf_smoothening;
60 u32 vbios_domains;
61 struct boardobjgrpmask_e32 prog_domains_mask;
62 struct boardobjgrpmask_e32 master_domains_mask;
63 u16 cntr_sampling_periodms;
64 struct ctrl_clk_clk_delta deltas;
65
66 struct clk_domain *ordered_noise_aware_list[CTRL_BOARDOBJ_MAX_BOARD_OBJECTS];
67
68 struct clk_domain *ordered_noise_unaware_list[CTRL_BOARDOBJ_MAX_BOARD_OBJECTS];
69};
70
71struct clk_domain {
72 struct boardobj super;
73 u32 api_domain;
74 u32 part_mask;
75 u8 domain;
76 u8 perf_domain_index;
77 u8 perf_domain_grp_idx;
78 u8 ratio_domain;
79 u8 usage;
80 clkproglink *clkdomainclkproglink;
81 clkvfsearch *clkdomainclkvfsearch;
82 clkgetfpoints *clkdomainclkgetfpoints;
83};
84
85struct clk_domain_3x {
86 struct clk_domain super;
87 bool b_noise_aware_capable;
88};
89
90struct clk_domain_3x_fixed {
91 struct clk_domain_3x super;
92 u16 freq_mhz;
93};
94
95struct clk_domain_3x_prog {
96 struct clk_domain_3x super;
97 u8 clk_prog_idx_first;
98 u8 clk_prog_idx_last;
99 u8 noise_unaware_ordering_index;
100 u8 noise_aware_ordering_index;
101 bool b_force_noise_unaware_ordering;
102 int factory_offset_khz;
103 short freq_delta_min_mhz;
104 short freq_delta_max_mhz;
105 struct ctrl_clk_clk_delta deltas;
106};
107
108struct clk_domain_3x_master {
109 struct clk_domain_3x_prog super;
110 u32 slave_idxs_mask;
111};
112
113struct clk_domain_3x_slave {
114 struct clk_domain_3x_prog super;
115 u8 master_idx;
116 clkgetslaveclk *clkdomainclkgetslaveclk;
117};
118
119u32 clk_domain_clk_prog_link(struct gk20a *g, struct clk_pmupstate *pclk);
120
121#define CLK_CLK_DOMAIN_GET(pclk, idx) \
122 ((struct clk_domain *)BOARDOBJGRP_OBJ_GET_BY_IDX( \
123 &pclk->clk_domainobjs.super.super, (u8)(idx)))
124
125#endif
diff --git a/drivers/gpu/nvgpu/clk/clk_fll.c b/drivers/gpu/nvgpu/clk/clk_fll.c
new file mode 100644
index 00000000..2f05448f
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk_fll.c
@@ -0,0 +1,444 @@
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 "boardobj/boardobjgrp.h"
29#include "boardobj/boardobjgrp_e32.h"
30#include "ctrl/ctrlclk.h"
31#include "ctrl/ctrlvolt.h"
32
33static u32 devinit_get_fll_device_table(struct gk20a *g,
34 struct avfsfllobjs *pfllobjs);
35static struct fll_device *construct_fll_device(struct gk20a *g,
36 void *pargs);
37static u32 fll_device_init_pmudata_super(struct gk20a *g,
38 struct boardobj *board_obj_ptr,
39 struct nv_pmu_boardobj *ppmudata);
40
41static u32 _clk_fll_devgrp_pmudatainit_super(struct gk20a *g,
42 struct boardobjgrp *pboardobjgrp,
43 struct nv_pmu_boardobjgrp_super *pboardobjgrppmu)
44{
45 struct nv_pmu_clk_clk_fll_device_boardobjgrp_set_header *pset =
46 (struct nv_pmu_clk_clk_fll_device_boardobjgrp_set_header *)
47 pboardobjgrppmu;
48 struct avfsfllobjs *pfll_objs = (struct avfsfllobjs *)
49 pboardobjgrp;
50 u32 status = 0;
51
52 gk20a_dbg_info("");
53
54 status = boardobjgrp_pmudatainit_e32(g, pboardobjgrp, pboardobjgrppmu);
55 if (status) {
56 nvgpu_err(g, "failed to init fll pmuobjgrp");
57 return status;
58 }
59 pset->lut_num_entries = pfll_objs->lut_num_entries;
60 pset->lut_step_size_uv = pfll_objs->lut_step_size_uv;
61 pset->lut_min_voltage_uv = pfll_objs->lut_min_voltage_uv;
62 pset->max_min_freq_mhz = pfll_objs->max_min_freq_mhz;
63
64 status = boardobjgrpmask_export(
65 &pfll_objs->lut_prog_master_mask.super,
66 pfll_objs->lut_prog_master_mask.super.bitcount,
67 &pset->lut_prog_master_mask.super);
68
69 gk20a_dbg_info(" Done");
70 return status;
71}
72
73static u32 _clk_fll_devgrp_pmudata_instget(struct gk20a *g,
74 struct nv_pmu_boardobjgrp *pmuboardobjgrp,
75 struct nv_pmu_boardobj **ppboardobjpmudata,
76 u8 idx)
77{
78 struct nv_pmu_clk_clk_fll_device_boardobj_grp_set *pgrp_set =
79 (struct nv_pmu_clk_clk_fll_device_boardobj_grp_set *)
80 pmuboardobjgrp;
81
82 gk20a_dbg_info("");
83
84 /*check whether pmuboardobjgrp has a valid boardobj in index*/
85 if (((u32)BIT(idx) &
86 pgrp_set->hdr.data.super.obj_mask.super.data[0]) == 0)
87 return -EINVAL;
88
89 *ppboardobjpmudata = (struct nv_pmu_boardobj *)
90 &pgrp_set->objects[idx].data.board_obj;
91 gk20a_dbg_info(" Done");
92 return 0;
93}
94
95static u32 _clk_fll_devgrp_pmustatus_instget(struct gk20a *g,
96 void *pboardobjgrppmu,
97 struct nv_pmu_boardobj_query **ppboardobjpmustatus,
98 u8 idx)
99{
100 struct nv_pmu_clk_clk_fll_device_boardobj_grp_get_status *pgrp_get_status =
101 (struct nv_pmu_clk_clk_fll_device_boardobj_grp_get_status *)
102 pboardobjgrppmu;
103
104 /*check whether pmuboardobjgrp has a valid boardobj in index*/
105 if (((u32)BIT(idx) &
106 pgrp_get_status->hdr.data.super.obj_mask.super.data[0]) == 0)
107 return -EINVAL;
108
109 *ppboardobjpmustatus = (struct nv_pmu_boardobj_query *)
110 &pgrp_get_status->objects[idx].data.board_obj;
111 return 0;
112}
113
114u32 clk_fll_sw_setup(struct gk20a *g)
115{
116 u32 status;
117 struct boardobjgrp *pboardobjgrp = NULL;
118 struct avfsfllobjs *pfllobjs;
119 struct fll_device *pfll;
120 struct fll_device *pfll_master;
121 struct fll_device *pfll_local;
122 u8 i;
123 u8 j;
124
125 gk20a_dbg_info("");
126
127 status = boardobjgrpconstruct_e32(g, &g->clk_pmu.avfs_fllobjs.super);
128 if (status) {
129 nvgpu_err(g,
130 "error creating boardobjgrp for fll, status - 0x%x", status);
131 goto done;
132 }
133 pfllobjs = &(g->clk_pmu.avfs_fllobjs);
134 pboardobjgrp = &(g->clk_pmu.avfs_fllobjs.super.super);
135
136 BOARDOBJGRP_PMU_CONSTRUCT(pboardobjgrp, CLK, FLL_DEVICE);
137
138 status = BOARDOBJGRP_PMU_CMD_GRP_SET_CONSTRUCT(g, pboardobjgrp,
139 clk, CLK, clk_fll_device, CLK_FLL_DEVICE);
140 if (status) {
141 nvgpu_err(g,
142 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
143 status);
144 goto done;
145 }
146
147 pboardobjgrp->pmudatainit = _clk_fll_devgrp_pmudatainit_super;
148 pboardobjgrp->pmudatainstget = _clk_fll_devgrp_pmudata_instget;
149 pboardobjgrp->pmustatusinstget = _clk_fll_devgrp_pmustatus_instget;
150 pfllobjs = (struct avfsfllobjs *)pboardobjgrp;
151 pfllobjs->lut_num_entries = CTRL_CLK_LUT_NUM_ENTRIES;
152 pfllobjs->lut_step_size_uv = CTRL_CLK_VIN_STEP_SIZE_UV;
153 pfllobjs->lut_min_voltage_uv = CTRL_CLK_LUT_MIN_VOLTAGE_UV;
154
155 /* Initialize lut prog master mask to zero.*/
156 boardobjgrpmask_e32_init(&pfllobjs->lut_prog_master_mask, NULL);
157
158 status = devinit_get_fll_device_table(g, pfllobjs);
159 if (status)
160 goto done;
161
162 status = BOARDOBJGRP_PMU_CMD_GRP_GET_STATUS_CONSTRUCT(g,
163 &g->clk_pmu.avfs_fllobjs.super.super,
164 clk, CLK, clk_fll_device, CLK_FLL_DEVICE);
165 if (status) {
166 nvgpu_err(g,
167 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
168 status);
169 goto done;
170 }
171
172 BOARDOBJGRP_FOR_EACH(&(pfllobjs->super.super),
173 struct fll_device *, pfll, i) {
174 pfll_master = NULL;
175 j = 0;
176 BOARDOBJGRP_ITERATOR(&(pfllobjs->super.super),
177 struct fll_device *, pfll_local, j,
178 &pfllobjs->lut_prog_master_mask.super) {
179 if (pfll_local->clk_domain == pfll->clk_domain) {
180 pfll_master = pfll_local;
181 break;
182 }
183 }
184
185 if (pfll_master == NULL) {
186 status = boardobjgrpmask_bitset(
187 &pfllobjs->lut_prog_master_mask.super,
188 BOARDOBJ_GET_IDX(pfll));
189 if (status) {
190 nvgpu_err(g, "err setting lutprogmask");
191 goto done;
192 }
193 pfll_master = pfll;
194 }
195 status = pfll_master->lut_broadcast_slave_register(
196 g, pfllobjs, pfll_master, pfll);
197
198 if (status) {
199 nvgpu_err(g, "err setting lutslavemask");
200 goto done;
201 }
202 }
203done:
204 gk20a_dbg_info(" done status %x", status);
205 return status;
206}
207
208u32 clk_fll_pmu_setup(struct gk20a *g)
209{
210 u32 status;
211 struct boardobjgrp *pboardobjgrp = NULL;
212
213 gk20a_dbg_info("");
214
215 pboardobjgrp = &g->clk_pmu.avfs_fllobjs.super.super;
216
217 if (!pboardobjgrp->bconstructed)
218 return -EINVAL;
219
220 status = pboardobjgrp->pmuinithandle(g, pboardobjgrp);
221
222 gk20a_dbg_info("Done");
223 return status;
224}
225
226static u32 devinit_get_fll_device_table(struct gk20a *g,
227 struct avfsfllobjs *pfllobjs)
228{
229 u32 status = 0;
230 u8 *fll_table_ptr = NULL;
231 struct fll_descriptor_header fll_desc_table_header_sz = { 0 };
232 struct fll_descriptor_header_10 fll_desc_table_header = { 0 };
233 struct fll_descriptor_entry_10 fll_desc_table_entry = { 0 };
234 u8 *fll_tbl_entry_ptr = NULL;
235 u32 index = 0;
236 struct fll_device fll_dev_data;
237 struct fll_device *pfll_dev;
238 struct vin_device *pvin_dev;
239 u32 desctablesize;
240 u32 vbios_domain = NV_PERF_DOMAIN_4X_CLOCK_DOMAIN_SKIP;
241 struct avfsvinobjs *pvinobjs = &g->clk_pmu.avfs_vinobjs;
242
243 gk20a_dbg_info("");
244
245 fll_table_ptr = (u8 *)nvgpu_bios_get_perf_table_ptrs(g,
246 g->bios.clock_token, FLL_TABLE);
247 if (fll_table_ptr == NULL) {
248 status = -1;
249 goto done;
250 }
251
252 memcpy(&fll_desc_table_header_sz, fll_table_ptr,
253 sizeof(struct fll_descriptor_header));
254 if (fll_desc_table_header_sz.size >= FLL_DESCRIPTOR_HEADER_10_SIZE_6)
255 desctablesize = FLL_DESCRIPTOR_HEADER_10_SIZE_6;
256 else
257 desctablesize = FLL_DESCRIPTOR_HEADER_10_SIZE_4;
258
259 memcpy(&fll_desc_table_header, fll_table_ptr, desctablesize);
260
261 if (desctablesize == FLL_DESCRIPTOR_HEADER_10_SIZE_6)
262 pfllobjs->max_min_freq_mhz =
263 fll_desc_table_header.max_min_freq_mhz;
264 else
265 pfllobjs->max_min_freq_mhz = 0;
266
267 /* Read table entries*/
268 fll_tbl_entry_ptr = fll_table_ptr + desctablesize;
269 for (index = 0; index < fll_desc_table_header.entry_count; index++) {
270 u32 fll_id;
271
272 memcpy(&fll_desc_table_entry, fll_tbl_entry_ptr,
273 sizeof(struct fll_descriptor_entry_10));
274
275 if (fll_desc_table_entry.fll_device_type == CTRL_CLK_FLL_TYPE_DISABLED)
276 continue;
277
278 fll_id = fll_desc_table_entry.fll_device_id;
279
280 pvin_dev = CLK_GET_VIN_DEVICE(pvinobjs,
281 (u8)fll_desc_table_entry.vin_idx_logic);
282 if (pvin_dev == NULL)
283 return -EINVAL;
284
285 pvin_dev->flls_shared_mask |= BIT(fll_id);
286
287 pvin_dev = CLK_GET_VIN_DEVICE(pvinobjs,
288 (u8)fll_desc_table_entry.vin_idx_sram);
289 if (pvin_dev == NULL)
290 return -EINVAL;
291
292 pvin_dev->flls_shared_mask |= BIT(fll_id);
293
294 fll_dev_data.super.type =
295 (u8)fll_desc_table_entry.fll_device_type;
296 fll_dev_data.id = (u8)fll_desc_table_entry.fll_device_id;
297 fll_dev_data.mdiv = (u8)BIOS_GET_FIELD(
298 fll_desc_table_entry.fll_params,
299 NV_FLL_DESC_FLL_PARAMS_MDIV);
300 fll_dev_data.input_freq_mhz =
301 (u16)fll_desc_table_entry.ref_freq_mhz;
302 fll_dev_data.min_freq_vfe_idx =
303 (u8)fll_desc_table_entry.min_freq_vfe_idx;
304 fll_dev_data.freq_ctrl_idx = CTRL_BOARDOBJ_IDX_INVALID;
305
306 vbios_domain = (u32)(fll_desc_table_entry.clk_domain &
307 NV_PERF_DOMAIN_4X_CLOCK_DOMAIN_MASK);
308 if (vbios_domain == 0)
309 fll_dev_data.clk_domain = CTRL_CLK_DOMAIN_GPC2CLK;
310 else if (vbios_domain == 1)
311 fll_dev_data.clk_domain = CTRL_CLK_DOMAIN_XBAR2CLK;
312 else if (vbios_domain == 3)
313 fll_dev_data.clk_domain = CTRL_CLK_DOMAIN_SYS2CLK;
314 else
315 continue;
316
317 fll_dev_data.rail_idx_for_lut = 0;
318
319 fll_dev_data.vin_idx_logic =
320 (u8)fll_desc_table_entry.vin_idx_logic;
321 fll_dev_data.vin_idx_sram =
322 (u8)fll_desc_table_entry.vin_idx_sram;
323 fll_dev_data.lut_device.vselect_mode =
324 (u8)BIOS_GET_FIELD(fll_desc_table_entry.lut_params,
325 NV_FLL_DESC_LUT_PARAMS_VSELECT);
326 fll_dev_data.lut_device.hysteresis_threshold =
327 (u8)BIOS_GET_FIELD(fll_desc_table_entry.lut_params,
328 NV_FLL_DESC_LUT_PARAMS_HYSTERISIS_THRESHOLD);
329 fll_dev_data.regime_desc.regime_id =
330 CTRL_CLK_FLL_REGIME_ID_FFR;
331 fll_dev_data.regime_desc.fixed_freq_regime_limit_mhz =
332 (u16)fll_desc_table_entry.ffr_cutoff_freq_mhz;
333
334 /*construct fll device*/
335 pfll_dev = construct_fll_device(g, (void *)&fll_dev_data);
336
337 status = boardobjgrp_objinsert(&pfllobjs->super.super,
338 (struct boardobj *)pfll_dev, index);
339
340 fll_tbl_entry_ptr += fll_desc_table_header.entry_size;
341 }
342
343done:
344 gk20a_dbg_info(" done status %x", status);
345 return status;
346}
347
348static u32 lutbroadcastslaveregister(struct gk20a *g,
349 struct avfsfllobjs *pfllobjs,
350 struct fll_device *pfll,
351 struct fll_device *pfll_slave)
352{
353 if (pfll->clk_domain != pfll_slave->clk_domain)
354 return -EINVAL;
355
356 return boardobjgrpmask_bitset(&pfll->
357 lut_prog_broadcast_slave_mask.super,
358 BOARDOBJ_GET_IDX(pfll_slave));
359}
360
361static struct fll_device *construct_fll_device(struct gk20a *g,
362 void *pargs)
363{
364 struct boardobj *board_obj_ptr = NULL;
365 struct fll_device *pfll_dev;
366 struct fll_device *board_obj_fll_ptr = NULL;
367 u32 status;
368
369 gk20a_dbg_info("");
370 status = boardobj_construct_super(g, &board_obj_ptr,
371 sizeof(struct fll_device), pargs);
372 if (status)
373 return NULL;
374
375 pfll_dev = (struct fll_device *)pargs;
376 board_obj_fll_ptr = (struct fll_device *)board_obj_ptr;
377 board_obj_ptr->pmudatainit = fll_device_init_pmudata_super;
378 board_obj_fll_ptr->lut_broadcast_slave_register =
379 lutbroadcastslaveregister;
380 board_obj_fll_ptr->id = pfll_dev->id;
381 board_obj_fll_ptr->mdiv = pfll_dev->mdiv;
382 board_obj_fll_ptr->rail_idx_for_lut = pfll_dev->rail_idx_for_lut;
383 board_obj_fll_ptr->input_freq_mhz = pfll_dev->input_freq_mhz;
384 board_obj_fll_ptr->clk_domain = pfll_dev->clk_domain;
385 board_obj_fll_ptr->vin_idx_logic = pfll_dev->vin_idx_logic;
386 board_obj_fll_ptr->vin_idx_sram = pfll_dev->vin_idx_sram;
387 board_obj_fll_ptr->min_freq_vfe_idx =
388 pfll_dev->min_freq_vfe_idx;
389 board_obj_fll_ptr->freq_ctrl_idx = pfll_dev->freq_ctrl_idx;
390 memcpy(&board_obj_fll_ptr->lut_device, &pfll_dev->lut_device,
391 sizeof(struct nv_pmu_clk_lut_device_desc));
392 memcpy(&board_obj_fll_ptr->regime_desc, &pfll_dev->regime_desc,
393 sizeof(struct nv_pmu_clk_regime_desc));
394 boardobjgrpmask_e32_init(
395 &board_obj_fll_ptr->lut_prog_broadcast_slave_mask, NULL);
396
397 gk20a_dbg_info(" Done");
398
399 return (struct fll_device *)board_obj_ptr;
400}
401
402static u32 fll_device_init_pmudata_super(struct gk20a *g,
403 struct boardobj *board_obj_ptr,
404 struct nv_pmu_boardobj *ppmudata)
405{
406 u32 status = 0;
407 struct fll_device *pfll_dev;
408 struct nv_pmu_clk_clk_fll_device_boardobj_set *perf_pmu_data;
409
410 gk20a_dbg_info("");
411
412 status = boardobj_pmudatainit_super(g, board_obj_ptr, ppmudata);
413 if (status != 0)
414 return status;
415
416 pfll_dev = (struct fll_device *)board_obj_ptr;
417 perf_pmu_data = (struct nv_pmu_clk_clk_fll_device_boardobj_set *)
418 ppmudata;
419
420 perf_pmu_data->id = pfll_dev->id;
421 perf_pmu_data->mdiv = pfll_dev->mdiv;
422 perf_pmu_data->rail_idx_for_lut = pfll_dev->rail_idx_for_lut;
423 perf_pmu_data->input_freq_mhz = pfll_dev->input_freq_mhz;
424 perf_pmu_data->vin_idx_logic = pfll_dev->vin_idx_logic;
425 perf_pmu_data->vin_idx_sram = pfll_dev->vin_idx_sram;
426 perf_pmu_data->clk_domain = pfll_dev->clk_domain;
427 perf_pmu_data->min_freq_vfe_idx =
428 pfll_dev->min_freq_vfe_idx;
429 perf_pmu_data->freq_ctrl_idx = pfll_dev->freq_ctrl_idx;
430
431 memcpy(&perf_pmu_data->lut_device, &pfll_dev->lut_device,
432 sizeof(struct nv_pmu_clk_lut_device_desc));
433 memcpy(&perf_pmu_data->regime_desc, &pfll_dev->regime_desc,
434 sizeof(struct nv_pmu_clk_regime_desc));
435
436 status = boardobjgrpmask_export(
437 &pfll_dev->lut_prog_broadcast_slave_mask.super,
438 pfll_dev->lut_prog_broadcast_slave_mask.super.bitcount,
439 &perf_pmu_data->lut_prog_broadcast_slave_mask.super);
440
441 gk20a_dbg_info(" Done");
442
443 return status;
444}
diff --git a/drivers/gpu/nvgpu/clk/clk_fll.h b/drivers/gpu/nvgpu/clk/clk_fll.h
new file mode 100644
index 00000000..481ca707
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk_fll.h
@@ -0,0 +1,77 @@
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#ifndef _CLKFLL_H_
24#define _CLKFLL_H_
25
26#include <nvgpu/pmuif/nvgpu_gpmu_cmdif.h>
27#include "boardobj/boardobjgrp_e32.h"
28#include "boardobj/boardobjgrpmask.h"
29
30/*data and function definition to talk to driver*/
31u32 clk_fll_sw_setup(struct gk20a *g);
32u32 clk_fll_pmu_setup(struct gk20a *g);
33
34struct avfsfllobjs {
35 struct boardobjgrp_e32 super;
36 struct boardobjgrpmask_e32 lut_prog_master_mask;
37 u32 lut_step_size_uv;
38 u32 lut_min_voltage_uv;
39 u8 lut_num_entries;
40 u16 max_min_freq_mhz;
41};
42
43struct fll_device;
44
45typedef u32 fll_lut_broadcast_slave_register(struct gk20a *g,
46 struct avfsfllobjs *pfllobjs,
47 struct fll_device *pfll,
48 struct fll_device *pfll_slave);
49
50struct fll_device {
51 struct boardobj super;
52 u8 id;
53 u8 mdiv;
54 u16 input_freq_mhz;
55 u32 clk_domain;
56 u8 vin_idx_logic;
57 u8 vin_idx_sram;
58 u8 rail_idx_for_lut;
59 struct nv_pmu_clk_lut_device_desc lut_device;
60 struct nv_pmu_clk_regime_desc regime_desc;
61 u8 min_freq_vfe_idx;
62 u8 freq_ctrl_idx;
63 u8 target_regime_id_override;
64 struct boardobjgrpmask_e32 lut_prog_broadcast_slave_mask;
65 fll_lut_broadcast_slave_register *lut_broadcast_slave_register;
66};
67
68#define CLK_FLL_LUT_VF_NUM_ENTRIES(pclk) \
69 (pclk->avfs_fllobjs.lut_num_entries)
70
71#define CLK_FLL_LUT_MIN_VOLTAGE_UV(pclk) \
72 (pclk->avfs_fllobjs.lut_min_voltage_uv)
73#define CLK_FLL_LUT_STEP_SIZE_UV(pclk) \
74 (pclk->avfs_fllobjs.lut_step_size_uv)
75
76#endif
77
diff --git a/drivers/gpu/nvgpu/clk/clk_freq_controller.c b/drivers/gpu/nvgpu/clk/clk_freq_controller.c
new file mode 100644
index 00000000..f5c1e929
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk_freq_controller.c
@@ -0,0 +1,455 @@
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 "clk_freq_controller.h"
30#include "boardobj/boardobjgrp.h"
31#include "boardobj/boardobjgrp_e32.h"
32#include "ctrl/ctrlclk.h"
33#include "ctrl/ctrlvolt.h"
34
35static u32 clk_freq_controller_pmudatainit_super(struct gk20a *g,
36 struct boardobj *board_obj_ptr,
37 struct nv_pmu_boardobj *ppmudata)
38{
39 struct nv_pmu_clk_clk_freq_controller_boardobj_set *pfreq_cntlr_set;
40 struct clk_freq_controller *pfreq_cntlr;
41 u32 status = 0;
42
43 status = boardobj_pmudatainit_super(g, board_obj_ptr, ppmudata);
44 if (status)
45 return status;
46
47 pfreq_cntlr_set =
48 (struct nv_pmu_clk_clk_freq_controller_boardobj_set *)ppmudata;
49 pfreq_cntlr = (struct clk_freq_controller *)board_obj_ptr;
50
51 pfreq_cntlr_set->controller_id = pfreq_cntlr->controller_id;
52 pfreq_cntlr_set->clk_domain = pfreq_cntlr->clk_domain;
53 pfreq_cntlr_set->parts_freq_mode = pfreq_cntlr->parts_freq_mode;
54 pfreq_cntlr_set->bdisable = pfreq_cntlr->bdisable;
55 pfreq_cntlr_set->freq_cap_noise_unaware_vmin_above =
56 pfreq_cntlr->freq_cap_noise_unaware_vmin_above;
57 pfreq_cntlr_set->freq_cap_noise_unaware_vmin_below =
58 pfreq_cntlr->freq_cap_noise_unaware_vmin_below;
59 pfreq_cntlr_set->freq_hyst_pos_mhz = pfreq_cntlr->freq_hyst_pos_mhz;
60 pfreq_cntlr_set->freq_hyst_neg_mhz = pfreq_cntlr->freq_hyst_neg_mhz;
61
62 return status;
63}
64
65static u32 clk_freq_controller_pmudatainit_pi(struct gk20a *g,
66 struct boardobj *board_obj_ptr,
67 struct nv_pmu_boardobj *ppmudata)
68{
69 struct nv_pmu_clk_clk_freq_controller_pi_boardobj_set
70 *pfreq_cntlr_pi_set;
71 struct clk_freq_controller_pi *pfreq_cntlr_pi;
72 u32 status = 0;
73
74 status = clk_freq_controller_pmudatainit_super(g,
75 board_obj_ptr, ppmudata);
76 if (status)
77 return -1;
78
79 pfreq_cntlr_pi_set =
80 (struct nv_pmu_clk_clk_freq_controller_pi_boardobj_set *)
81 ppmudata;
82 pfreq_cntlr_pi = (struct clk_freq_controller_pi *)board_obj_ptr;
83
84 pfreq_cntlr_pi_set->prop_gain = pfreq_cntlr_pi->prop_gain;
85 pfreq_cntlr_pi_set->integ_gain = pfreq_cntlr_pi->integ_gain;
86 pfreq_cntlr_pi_set->integ_decay = pfreq_cntlr_pi->integ_decay;
87 pfreq_cntlr_pi_set->volt_delta_min = pfreq_cntlr_pi->volt_delta_min;
88 pfreq_cntlr_pi_set->volt_delta_max = pfreq_cntlr_pi->volt_delta_max;
89 pfreq_cntlr_pi_set->slowdown_pct_min = pfreq_cntlr_pi->slowdown_pct_min;
90 pfreq_cntlr_pi_set->bpoison = pfreq_cntlr_pi->bpoison;
91
92 return status;
93}
94
95static u32 clk_freq_controller_construct_super(struct gk20a *g,
96 struct boardobj **ppboardobj,
97 u16 size, void *pargs)
98{
99 struct clk_freq_controller *pfreq_cntlr = NULL;
100 struct clk_freq_controller *pfreq_cntlr_tmp = NULL;
101 u32 status = 0;
102
103 status = boardobj_construct_super(g, ppboardobj, size, pargs);
104 if (status)
105 return -EINVAL;
106
107 pfreq_cntlr_tmp = (struct clk_freq_controller *)pargs;
108 pfreq_cntlr = (struct clk_freq_controller *)*ppboardobj;
109
110 pfreq_cntlr->super.pmudatainit = clk_freq_controller_pmudatainit_super;
111
112 pfreq_cntlr->controller_id = pfreq_cntlr_tmp->controller_id;
113 pfreq_cntlr->clk_domain = pfreq_cntlr_tmp->clk_domain;
114 pfreq_cntlr->parts_freq_mode = pfreq_cntlr_tmp->parts_freq_mode;
115 pfreq_cntlr->freq_cap_noise_unaware_vmin_above =
116 pfreq_cntlr_tmp->freq_cap_noise_unaware_vmin_above;
117 pfreq_cntlr->freq_cap_noise_unaware_vmin_below =
118 pfreq_cntlr_tmp->freq_cap_noise_unaware_vmin_below;
119 pfreq_cntlr->freq_hyst_pos_mhz = pfreq_cntlr_tmp->freq_hyst_pos_mhz;
120 pfreq_cntlr->freq_hyst_neg_mhz = pfreq_cntlr_tmp->freq_hyst_neg_mhz;
121
122 return status;
123}
124
125static u32 clk_freq_controller_construct_pi(struct gk20a *g,
126 struct boardobj **ppboardobj,
127 u16 size, void *pargs)
128{
129 struct clk_freq_controller_pi *pfreq_cntlr_pi = NULL;
130 struct clk_freq_controller_pi *pfreq_cntlr_pi_tmp = NULL;
131 u32 status = 0;
132
133 status = clk_freq_controller_construct_super(g, ppboardobj,
134 size, pargs);
135 if (status)
136 return -EINVAL;
137
138 pfreq_cntlr_pi = (struct clk_freq_controller_pi *)*ppboardobj;
139 pfreq_cntlr_pi_tmp = (struct clk_freq_controller_pi *)pargs;
140
141 pfreq_cntlr_pi->super.super.pmudatainit =
142 clk_freq_controller_pmudatainit_pi;
143
144 pfreq_cntlr_pi->prop_gain = pfreq_cntlr_pi_tmp->prop_gain;
145 pfreq_cntlr_pi->integ_gain = pfreq_cntlr_pi_tmp->integ_gain;
146 pfreq_cntlr_pi->integ_decay = pfreq_cntlr_pi_tmp->integ_decay;
147 pfreq_cntlr_pi->volt_delta_min = pfreq_cntlr_pi_tmp->volt_delta_min;
148 pfreq_cntlr_pi->volt_delta_max = pfreq_cntlr_pi_tmp->volt_delta_max;
149 pfreq_cntlr_pi->slowdown_pct_min = pfreq_cntlr_pi_tmp->slowdown_pct_min;
150 pfreq_cntlr_pi->bpoison = pfreq_cntlr_pi_tmp->bpoison;
151
152 return status;
153}
154
155static struct clk_freq_controller *clk_clk_freq_controller_construct(
156 struct gk20a *g,
157 void *pargs)
158{
159 struct boardobj *board_obj_ptr = NULL;
160 u32 status = 0;
161
162 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_CLK_CLK_FREQ_CONTROLLER_TYPE_PI)
163 return NULL;
164
165 status = clk_freq_controller_construct_pi(g, &board_obj_ptr,
166 sizeof(struct clk_freq_controller_pi), pargs);
167 if (status)
168 return NULL;
169
170 return (struct clk_freq_controller *)board_obj_ptr;
171}
172
173
174static u32 clk_get_freq_controller_table(struct gk20a *g,
175 struct clk_freq_controllers *pclk_freq_controllers)
176{
177 u32 status = 0;
178 u8 *pfreq_controller_table_ptr = NULL;
179 struct vbios_fct_1x_header header = { 0 };
180 struct vbios_fct_1x_entry entry = { 0 };
181 u8 entry_idx;
182 u8 *entry_offset;
183 u32 freq_controller_id;
184 struct clk_freq_controller *pclk_freq_cntr = NULL;
185 struct clk_freq_controller *ptmp_freq_cntr = NULL;
186 struct clk_freq_controller_pi *ptmp_freq_cntr_pi = NULL;
187 struct clk_domain *pclk_domain;
188
189 struct freq_controller_data_type {
190 union {
191 struct boardobj board_obj;
192 struct clk_freq_controller freq_controller;
193 struct clk_freq_controller_pi freq_controller_pi;
194 };
195 } freq_controller_data;
196
197 pfreq_controller_table_ptr =
198 (u8 *)nvgpu_bios_get_perf_table_ptrs(g,
199 g->bios.clock_token,
200 FREQUENCY_CONTROLLER_TABLE);
201 if (pfreq_controller_table_ptr == NULL) {
202 status = -EINVAL;
203 goto done;
204 }
205
206 memcpy(&header, pfreq_controller_table_ptr,
207 sizeof(struct vbios_fct_1x_header));
208
209 pclk_freq_controllers->sampling_period_ms = header.sampling_period_ms;
210 pclk_freq_controllers->volt_policy_idx = 0;
211
212 /* Read in the entries. */
213 for (entry_idx = 0; entry_idx < header.entry_count; entry_idx++) {
214 entry_offset = (pfreq_controller_table_ptr +
215 header.header_size + (entry_idx * header.entry_size));
216
217 memset(&freq_controller_data, 0x0,
218 sizeof(struct freq_controller_data_type));
219 ptmp_freq_cntr = &freq_controller_data.freq_controller;
220 ptmp_freq_cntr_pi = &freq_controller_data.freq_controller_pi;
221
222 memcpy(&entry, entry_offset,
223 sizeof(struct vbios_fct_1x_entry));
224
225 if (!BIOS_GET_FIELD(entry.flags0,
226 NV_VBIOS_FCT_1X_ENTRY_FLAGS0_TYPE))
227 continue;
228
229 freq_controller_data.board_obj.type = (u8)BIOS_GET_FIELD(
230 entry.flags0, NV_VBIOS_FCT_1X_ENTRY_FLAGS0_TYPE);
231
232 ptmp_freq_cntr->controller_id =
233 (u8)BIOS_GET_FIELD(entry.param0,
234 NV_VBIOS_FCT_1X_ENTRY_PARAM0_ID);
235
236 freq_controller_id = ptmp_freq_cntr->controller_id;
237
238 pclk_domain = CLK_CLK_DOMAIN_GET((&g->clk_pmu),
239 (u32)entry.clk_domain_idx);
240 freq_controller_data.freq_controller.clk_domain =
241 pclk_domain->api_domain;
242
243 ptmp_freq_cntr->parts_freq_mode =
244 (u8)BIOS_GET_FIELD(entry.param0,
245 NV_VBIOS_FCT_1X_ENTRY_PARAM0_FREQ_MODE);
246
247 /* Populate PI specific data */
248 ptmp_freq_cntr_pi->slowdown_pct_min =
249 (u8)BIOS_GET_FIELD(entry.param1,
250 NV_VBIOS_FCT_1X_ENTRY_PARAM1_SLOWDOWN_PCT_MIN);
251
252 ptmp_freq_cntr_pi->bpoison =
253 BIOS_GET_FIELD(entry.param1,
254 NV_VBIOS_FCT_1X_ENTRY_PARAM1_POISON);
255
256 ptmp_freq_cntr_pi->prop_gain =
257 (s32)BIOS_GET_FIELD(entry.param2,
258 NV_VBIOS_FCT_1X_ENTRY_PARAM2_PROP_GAIN);
259
260 ptmp_freq_cntr_pi->integ_gain =
261 (s32)BIOS_GET_FIELD(entry.param3,
262 NV_VBIOS_FCT_1X_ENTRY_PARAM3_INTEG_GAIN);
263
264 ptmp_freq_cntr_pi->integ_decay =
265 (s32)BIOS_GET_FIELD(entry.param4,
266 NV_VBIOS_FCT_1X_ENTRY_PARAM4_INTEG_DECAY);
267
268 ptmp_freq_cntr_pi->volt_delta_min =
269 (s32)BIOS_GET_FIELD(entry.param5,
270 NV_VBIOS_FCT_1X_ENTRY_PARAM5_VOLT_DELTA_MIN);
271
272 ptmp_freq_cntr_pi->volt_delta_max =
273 (s32)BIOS_GET_FIELD(entry.param6,
274 NV_VBIOS_FCT_1X_ENTRY_PARAM6_VOLT_DELTA_MAX);
275
276 ptmp_freq_cntr->freq_cap_noise_unaware_vmin_above =
277 (s16)BIOS_GET_FIELD(entry.param7,
278 NV_VBIOS_FCT_1X_ENTRY_PARAM7_FREQ_CAP_VF);
279
280 ptmp_freq_cntr->freq_cap_noise_unaware_vmin_below =
281 (s16)BIOS_GET_FIELD(entry.param7,
282 NV_VBIOS_FCT_1X_ENTRY_PARAM7_FREQ_CAP_VMIN);
283
284 ptmp_freq_cntr->freq_hyst_pos_mhz =
285 (s16)BIOS_GET_FIELD(entry.param8,
286 NV_VBIOS_FCT_1X_ENTRY_PARAM8_FREQ_HYST_POS);
287 ptmp_freq_cntr->freq_hyst_neg_mhz =
288 (s16)BIOS_GET_FIELD(entry.param8,
289 NV_VBIOS_FCT_1X_ENTRY_PARAM8_FREQ_HYST_NEG);
290
291 if (ptmp_freq_cntr_pi->volt_delta_max <
292 ptmp_freq_cntr_pi->volt_delta_min)
293 goto done;
294
295 pclk_freq_cntr = clk_clk_freq_controller_construct(g,
296 (void *)&freq_controller_data);
297
298 if (pclk_freq_cntr == NULL) {
299 nvgpu_err(g,
300 "unable to construct clock freq cntlr boardobj for %d",
301 entry_idx);
302 status = -EINVAL;
303 goto done;
304 }
305
306 status = boardobjgrp_objinsert(
307 &pclk_freq_controllers->super.super,
308 (struct boardobj *)pclk_freq_cntr, entry_idx);
309 if (status) {
310 nvgpu_err(g,
311 "unable to insert clock freq cntlr boardobj for");
312 status = -EINVAL;
313 goto done;
314 }
315
316 }
317
318done:
319 return status;
320}
321
322u32 clk_freq_controller_pmu_setup(struct gk20a *g)
323{
324 u32 status;
325 struct boardobjgrp *pboardobjgrp = NULL;
326
327 gk20a_dbg_info("");
328
329 pboardobjgrp = &g->clk_pmu.clk_freq_controllers.super.super;
330
331 if (!pboardobjgrp->bconstructed)
332 return -EINVAL;
333
334 status = pboardobjgrp->pmuinithandle(g, pboardobjgrp);
335
336 gk20a_dbg_info("Done");
337 return status;
338}
339
340static u32 _clk_freq_controller_devgrp_pmudata_instget(struct gk20a *g,
341 struct nv_pmu_boardobjgrp *pmuboardobjgrp,
342 struct nv_pmu_boardobj **ppboardobjpmudata,
343 u8 idx)
344{
345 struct nv_pmu_clk_clk_freq_controller_boardobj_grp_set *pgrp_set =
346 (struct nv_pmu_clk_clk_freq_controller_boardobj_grp_set *)
347 pmuboardobjgrp;
348
349 gk20a_dbg_info("");
350
351 /*check whether pmuboardobjgrp has a valid boardobj in index*/
352 if (((u32)BIT(idx) &
353 pgrp_set->hdr.data.super.obj_mask.super.data[0]) == 0)
354 return -EINVAL;
355
356 *ppboardobjpmudata = (struct nv_pmu_boardobj *)
357 &pgrp_set->objects[idx].data.board_obj;
358 gk20a_dbg_info(" Done");
359 return 0;
360}
361
362static u32 _clk_freq_controllers_pmudatainit(struct gk20a *g,
363 struct boardobjgrp *pboardobjgrp,
364 struct nv_pmu_boardobjgrp_super *pboardobjgrppmu)
365{
366 struct nv_pmu_clk_clk_freq_controller_boardobjgrp_set_header *pset =
367 (struct nv_pmu_clk_clk_freq_controller_boardobjgrp_set_header *)
368 pboardobjgrppmu;
369 struct clk_freq_controllers *pcntrs =
370 (struct clk_freq_controllers *)pboardobjgrp;
371 u32 status = 0;
372
373 status = boardobjgrp_pmudatainit_e32(g, pboardobjgrp, pboardobjgrppmu);
374 if (status) {
375 nvgpu_err(g,
376 "error updating pmu boardobjgrp for clk freq ctrs 0x%x",
377 status);
378 goto done;
379 }
380 pset->sampling_period_ms = pcntrs->sampling_period_ms;
381 pset->volt_policy_idx = pcntrs->volt_policy_idx;
382
383done:
384 return status;
385}
386
387u32 clk_freq_controller_sw_setup(struct gk20a *g)
388{
389 u32 status = 0;
390 struct boardobjgrp *pboardobjgrp = NULL;
391 struct clk_freq_controllers *pclk_freq_controllers;
392 struct avfsfllobjs *pfllobjs = &(g->clk_pmu.avfs_fllobjs);
393 struct fll_device *pfll;
394 struct clk_freq_controller *pclkfreqctrl;
395 u8 i;
396 u8 j;
397
398 gk20a_dbg_info("");
399
400 pclk_freq_controllers = &g->clk_pmu.clk_freq_controllers;
401 status = boardobjgrpconstruct_e32(g, &pclk_freq_controllers->super);
402 if (status) {
403 nvgpu_err(g,
404 "error creating boardobjgrp for clk FCT, status - 0x%x",
405 status);
406 goto done;
407 }
408
409 pboardobjgrp = &g->clk_pmu.clk_freq_controllers.super.super;
410
411 pboardobjgrp->pmudatainit = _clk_freq_controllers_pmudatainit;
412 pboardobjgrp->pmudatainstget =
413 _clk_freq_controller_devgrp_pmudata_instget;
414 pboardobjgrp->pmustatusinstget = NULL;
415
416 /* Initialize mask to zero.*/
417 boardobjgrpmask_e32_init(&pclk_freq_controllers->freq_ctrl_load_mask,
418 NULL);
419
420 BOARDOBJGRP_PMU_CONSTRUCT(pboardobjgrp, CLK, CLK_FREQ_CONTROLLER);
421
422 status = BOARDOBJGRP_PMU_CMD_GRP_SET_CONSTRUCT(g, pboardobjgrp,
423 clk, CLK, clk_freq_controller, CLK_FREQ_CONTROLLER);
424 if (status) {
425 nvgpu_err(g,
426 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
427 status);
428 goto done;
429 }
430
431 status = clk_get_freq_controller_table(g, pclk_freq_controllers);
432 if (status) {
433 nvgpu_err(g, "error reading freq controller table - 0x%x",
434 status);
435 goto done;
436 }
437
438 BOARDOBJGRP_FOR_EACH(&(pclk_freq_controllers->super.super),
439 struct clk_freq_controller *, pclkfreqctrl, i) {
440 pfll = NULL;
441 j = 0;
442 BOARDOBJGRP_FOR_EACH(&(pfllobjs->super.super),
443 struct fll_device *, pfll, j) {
444 if (pclkfreqctrl->controller_id == pfll->id) {
445 pfll->freq_ctrl_idx = i;
446 break;
447 }
448 }
449 boardobjgrpmask_bitset(&pclk_freq_controllers->
450 freq_ctrl_load_mask.super, i);
451 }
452done:
453 gk20a_dbg_info(" done status %x", status);
454 return status;
455}
diff --git a/drivers/gpu/nvgpu/clk/clk_freq_controller.h b/drivers/gpu/nvgpu/clk/clk_freq_controller.h
new file mode 100644
index 00000000..1b8a24c9
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk_freq_controller.h
@@ -0,0 +1,84 @@
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#ifndef _CLK_FREQ_CONTROLLER_H_
24#define _CLK_FREQ_CONTROLLER_H_
25
26#define CTRL_CLK_CLK_FREQ_CONTROLLER_ID_ALL 0xFF
27#define CTRL_CLK_CLK_FREQ_CONTROLLER_ID_SYS 0x00
28#define CTRL_CLK_CLK_FREQ_CONTROLLER_ID_LTC 0x01
29#define CTRL_CLK_CLK_FREQ_CONTROLLER_ID_XBAR 0x02
30#define CTRL_CLK_CLK_FREQ_CONTROLLER_ID_GPC0 0x03
31#define CTRL_CLK_CLK_FREQ_CONTROLLER_ID_GPC1 0x04
32#define CTRL_CLK_CLK_FREQ_CONTROLLER_ID_GPC2 0x05
33#define CTRL_CLK_CLK_FREQ_CONTROLLER_ID_GPC3 0x06
34#define CTRL_CLK_CLK_FREQ_CONTROLLER_ID_GPC4 0x07
35#define CTRL_CLK_CLK_FREQ_CONTROLLER_ID_GPC5 0x08
36#define CTRL_CLK_CLK_FREQ_CONTROLLER_ID_GPCS 0x09
37
38#define CTRL_CLK_CLK_FREQ_CONTROLLER_MASK_UNICAST_GPC \
39 (BIT(CTRL_CLK_CLK_FREQ_CONTROLLER_ID_GPC0) | \
40 BIT(CTRL_CLK_CLK_FREQ_CONTROLLER_ID_GPC1) | \
41 BIT(CTRL_CLK_CLK_FREQ_CONTROLLER_ID_GPC2) | \
42 BIT(CTRL_CLK_CLK_FREQ_CONTROLLER_ID_GPC3) | \
43 BIT(CTRL_CLK_CLK_FREQ_CONTROLLER_ID_GPC4) | \
44 BIT(CTRL_CLK_CLK_FREQ_CONTROLLER_ID_GPC5))
45
46#define CTRL_CLK_CLK_FREQ_CONTROLLER_TYPE_DISABLED 0x00
47#define CTRL_CLK_CLK_FREQ_CONTROLLER_TYPE_PI 0x01
48
49
50struct clk_freq_controller {
51 struct boardobj super;
52 u8 controller_id;
53 u8 parts_freq_mode;
54 bool bdisable;
55 u32 clk_domain;
56 s16 freq_cap_noise_unaware_vmin_above;
57 s16 freq_cap_noise_unaware_vmin_below;
58 s16 freq_hyst_pos_mhz;
59 s16 freq_hyst_neg_mhz;
60};
61
62struct clk_freq_controller_pi {
63 struct clk_freq_controller super;
64 s32 prop_gain;
65 s32 integ_gain;
66 s32 integ_decay;
67 s32 volt_delta_min;
68 s32 volt_delta_max;
69 u8 slowdown_pct_min;
70 bool bpoison;
71};
72
73struct clk_freq_controllers {
74 struct boardobjgrp_e32 super;
75 u32 sampling_period_ms;
76 struct boardobjgrpmask_e32 freq_ctrl_load_mask;
77 u8 volt_policy_idx;
78 void *pprereq_load;
79};
80
81u32 clk_freq_controller_sw_setup(struct gk20a *g);
82u32 clk_freq_controller_pmu_setup(struct gk20a *g);
83
84#endif
diff --git a/drivers/gpu/nvgpu/clk/clk_mclk.h b/drivers/gpu/nvgpu/clk/clk_mclk.h
new file mode 100644
index 00000000..a0d3fd5d
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk_mclk.h
@@ -0,0 +1,60 @@
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#ifndef _CLKMCLK_H_
24#define _CLKMCLK_H_
25
26#include <nvgpu/lock.h>
27
28#define GP106_MCLK_LOW_SPEED 0
29#define GP106_MCLK_MID_SPEED 1
30#define GP106_MCLK_HIGH_SPEED 2
31#define GP106_MCLK_NUM_SPEED 3
32
33enum gk20a_mclk_speed {
34 gk20a_mclk_low_speed,
35 gk20a_mclk_mid_speed,
36 gk20a_mclk_high_speed,
37};
38
39struct clk_mclk_state {
40 u32 speed;
41 struct nvgpu_mutex mclk_lock;
42 struct nvgpu_mutex data_lock;
43
44 u16 p5_min;
45 u16 p0_min;
46
47 void *vreg_buf;
48 bool init;
49
50#ifdef CONFIG_DEBUG_FS
51 s64 switch_max;
52 s64 switch_min;
53 u64 switch_num;
54 s64 switch_avg;
55 s64 switch_std;
56 bool debugfs_set;
57#endif
58};
59
60#endif
diff --git a/drivers/gpu/nvgpu/clk/clk_prog.c b/drivers/gpu/nvgpu/clk/clk_prog.c
new file mode 100644
index 00000000..6b5315b4
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk_prog.c
@@ -0,0 +1,1109 @@
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#include <nvgpu/kmem.h>
25
26#include "gk20a/gk20a.h"
27#include "clk.h"
28#include "clk_prog.h"
29#include "clk_vf_point.h"
30#include "boardobj/boardobjgrp.h"
31#include "boardobj/boardobjgrp_e32.h"
32#include "gp106/bios_gp106.h"
33#include "ctrl/ctrlclk.h"
34#include "ctrl/ctrlvolt.h"
35
36static struct clk_prog *construct_clk_prog(struct gk20a *g, void *pargs);
37static u32 devinit_get_clk_prog_table(struct gk20a *g,
38 struct clk_progs *pprogobjs);
39static vf_flatten vfflatten_prog_1x_master;
40static vf_lookup vflookup_prog_1x_master;
41static get_fpoints getfpoints_prog_1x_master;
42static get_slaveclk getslaveclk_prog_1x_master;
43
44static u32 _clk_progs_pmudatainit(struct gk20a *g,
45 struct boardobjgrp *pboardobjgrp,
46 struct nv_pmu_boardobjgrp_super *pboardobjgrppmu)
47{
48 struct nv_pmu_clk_clk_prog_boardobjgrp_set_header *pset =
49 (struct nv_pmu_clk_clk_prog_boardobjgrp_set_header *)
50 pboardobjgrppmu;
51 struct clk_progs *pprogs = (struct clk_progs *)pboardobjgrp;
52 u32 status = 0;
53
54 status = boardobjgrp_pmudatainit_e32(g, pboardobjgrp, pboardobjgrppmu);
55 if (status) {
56 nvgpu_err(g, "error updating pmu boardobjgrp for clk prog 0x%x",
57 status);
58 goto done;
59 }
60 pset->slave_entry_count = pprogs->slave_entry_count;
61 pset->vf_entry_count = pprogs->vf_entry_count;
62
63done:
64 return status;
65}
66
67static u32 _clk_progs_pmudata_instget(struct gk20a *g,
68 struct nv_pmu_boardobjgrp *pmuboardobjgrp,
69 struct nv_pmu_boardobj **ppboardobjpmudata,
70 u8 idx)
71{
72 struct nv_pmu_clk_clk_prog_boardobj_grp_set *pgrp_set =
73 (struct nv_pmu_clk_clk_prog_boardobj_grp_set *)pmuboardobjgrp;
74
75 gk20a_dbg_info("");
76
77 /*check whether pmuboardobjgrp has a valid boardobj in index*/
78 if (((u32)BIT(idx) &
79 pgrp_set->hdr.data.super.obj_mask.super.data[0]) == 0)
80 return -EINVAL;
81
82 *ppboardobjpmudata = (struct nv_pmu_boardobj *)
83 &pgrp_set->objects[idx].data.board_obj;
84 gk20a_dbg_info(" Done");
85 return 0;
86}
87
88u32 clk_prog_sw_setup(struct gk20a *g)
89{
90 u32 status;
91 struct boardobjgrp *pboardobjgrp = NULL;
92 struct clk_progs *pclkprogobjs;
93
94 gk20a_dbg_info("");
95
96 status = boardobjgrpconstruct_e255(g, &g->clk_pmu.clk_progobjs.super);
97 if (status) {
98 nvgpu_err(g,
99 "error creating boardobjgrp for clk prog, status - 0x%x",
100 status);
101 goto done;
102 }
103
104 pboardobjgrp = &g->clk_pmu.clk_progobjs.super.super;
105 pclkprogobjs = &(g->clk_pmu.clk_progobjs);
106
107 BOARDOBJGRP_PMU_CONSTRUCT(pboardobjgrp, CLK, CLK_PROG);
108
109 status = BOARDOBJGRP_PMU_CMD_GRP_SET_CONSTRUCT(g, pboardobjgrp,
110 clk, CLK, clk_prog, CLK_PROG);
111 if (status) {
112 nvgpu_err(g,
113 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
114 status);
115 goto done;
116 }
117
118 pboardobjgrp->pmudatainit = _clk_progs_pmudatainit;
119 pboardobjgrp->pmudatainstget = _clk_progs_pmudata_instget;
120
121 status = devinit_get_clk_prog_table(g, pclkprogobjs);
122 if (status)
123 goto done;
124
125 status = clk_domain_clk_prog_link(g, &g->clk_pmu);
126 if (status) {
127 nvgpu_err(g, "error constructing VF point board objects");
128 goto done;
129 }
130
131
132done:
133 gk20a_dbg_info(" done status %x", status);
134 return status;
135}
136
137u32 clk_prog_pmu_setup(struct gk20a *g)
138{
139 u32 status;
140 struct boardobjgrp *pboardobjgrp = NULL;
141
142 gk20a_dbg_info("");
143
144 pboardobjgrp = &g->clk_pmu.clk_progobjs.super.super;
145
146 if (!pboardobjgrp->bconstructed)
147 return -EINVAL;
148
149 status = pboardobjgrp->pmuinithandle(g, pboardobjgrp);
150
151 gk20a_dbg_info("Done");
152 return status;
153}
154
155static u32 devinit_get_clk_prog_table(struct gk20a *g,
156 struct clk_progs *pclkprogobjs)
157{
158 u32 status = 0;
159 u8 *clkprogs_tbl_ptr = NULL;
160 struct vbios_clock_programming_table_1x_header header = { 0 };
161 struct vbios_clock_programming_table_1x_entry prog = { 0 };
162 struct vbios_clock_programming_table_1x_slave_entry slaveprog = { 0 };
163 struct vbios_clock_programming_table_1x_vf_entry vfprog = { 0 };
164 u8 *entry = NULL;
165 u8 *slaveentry = NULL;
166 u8 *vfentry = NULL;
167 u32 i, j = 0;
168 struct clk_prog *pprog;
169 u8 prog_type;
170 u32 szfmt = VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_SIZE_0D;
171 u32 hszfmt = VBIOS_CLOCK_PROGRAMMING_TABLE_1X_HEADER_SIZE_08;
172 u32 slaveszfmt = VBIOS_CLOCK_PROGRAMMING_TABLE_1X_SLAVE_ENTRY_SIZE_03;
173 u32 vfszfmt = VBIOS_CLOCK_PROGRAMMING_TABLE_1X_VF_ENTRY_SIZE_02;
174 struct ctrl_clk_clk_prog_1x_master_vf_entry
175 vfentries[CTRL_CLK_CLK_PROG_1X_MASTER_VF_ENTRY_MAX_ENTRIES];
176 struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry
177 ratioslaveentries[CTRL_CLK_PROG_1X_MASTER_MAX_SLAVE_ENTRIES];
178 struct ctrl_clk_clk_prog_1x_master_table_slave_entry
179 tableslaveentries[CTRL_CLK_PROG_1X_MASTER_MAX_SLAVE_ENTRIES];
180 union {
181 struct boardobj board_obj;
182 struct clk_prog clkprog;
183 struct clk_prog_1x v1x;
184 struct clk_prog_1x_master v1x_master;
185 struct clk_prog_1x_master_ratio v1x_master_ratio;
186 struct clk_prog_1x_master_table v1x_master_table;
187 } prog_data;
188
189 gk20a_dbg_info("");
190
191 clkprogs_tbl_ptr = (u8 *)nvgpu_bios_get_perf_table_ptrs(g,
192 g->bios.clock_token, CLOCK_PROGRAMMING_TABLE);
193 if (clkprogs_tbl_ptr == NULL) {
194 status = -EINVAL;
195 goto done;
196 }
197
198 memcpy(&header, clkprogs_tbl_ptr, hszfmt);
199 if (header.header_size < hszfmt) {
200 status = -EINVAL;
201 goto done;
202 }
203 hszfmt = header.header_size;
204
205 if (header.entry_size <= VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_SIZE_05)
206 szfmt = header.entry_size;
207 else if (header.entry_size <= VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_SIZE_0D)
208 szfmt = header.entry_size;
209 else {
210 status = -EINVAL;
211 goto done;
212 }
213
214 if (header.vf_entry_size < vfszfmt) {
215 status = -EINVAL;
216 goto done;
217 }
218 vfszfmt = header.vf_entry_size;
219 if (header.slave_entry_size < slaveszfmt) {
220 status = -EINVAL;
221 goto done;
222 }
223 slaveszfmt = header.slave_entry_size;
224 if (header.vf_entry_count > CTRL_CLK_CLK_DELTA_MAX_VOLT_RAILS) {
225 status = -EINVAL;
226 goto done;
227 }
228
229 pclkprogobjs->slave_entry_count = header.slave_entry_count;
230 pclkprogobjs->vf_entry_count = header.vf_entry_count;
231
232 for (i = 0; i < header.entry_count; i++) {
233 memset(&prog_data, 0x0, (u32)sizeof(prog_data));
234
235 /* Read table entries*/
236 entry = clkprogs_tbl_ptr + hszfmt +
237 (i * (szfmt + (header.slave_entry_count * slaveszfmt) +
238 (header.vf_entry_count * vfszfmt)));
239
240 memcpy(&prog, entry, szfmt);
241 memset(vfentries, 0xFF,
242 sizeof(struct ctrl_clk_clk_prog_1x_master_vf_entry) *
243 CTRL_CLK_CLK_PROG_1X_MASTER_VF_ENTRY_MAX_ENTRIES);
244 memset(ratioslaveentries, 0xFF,
245 sizeof(struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry) *
246 CTRL_CLK_PROG_1X_MASTER_MAX_SLAVE_ENTRIES);
247 memset(tableslaveentries, 0xFF,
248 sizeof(struct ctrl_clk_clk_prog_1x_master_table_slave_entry) *
249 CTRL_CLK_PROG_1X_MASTER_MAX_SLAVE_ENTRIES);
250 prog_type = (u8)BIOS_GET_FIELD(prog.flags0,
251 NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_SOURCE);
252
253 switch (prog_type) {
254 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_SOURCE_PLL:
255 prog_data.v1x.source = CTRL_CLK_PROG_1X_SOURCE_PLL;
256 prog_data.v1x.source_data.pll.pll_idx =
257 (u8)BIOS_GET_FIELD(prog.param0,
258 NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_PARAM0_PLL_PLL_INDEX);
259 prog_data.v1x.source_data.pll.freq_step_size_mhz =
260 (u8)BIOS_GET_FIELD(prog.param1,
261 NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_PARAM1_PLL_FREQ_STEP_SIZE);
262 break;
263
264 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_SOURCE_ONE_SOURCE:
265 prog_data.v1x.source = CTRL_CLK_PROG_1X_SOURCE_ONE_SOURCE;
266 break;
267
268 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_SOURCE_FLL:
269 prog_data.v1x.source = CTRL_CLK_PROG_1X_SOURCE_FLL;
270 break;
271
272 default:
273 nvgpu_err(g, "invalid source %d", prog_type);
274 status = -EINVAL;
275 goto done;
276 }
277
278 prog_data.v1x.freq_max_mhz = (u16)prog.freq_max_mhz;
279
280 prog_type = (u8)BIOS_GET_FIELD(prog.flags0,
281 NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE);
282
283 vfentry = entry + szfmt +
284 header.slave_entry_count * slaveszfmt;
285 slaveentry = entry + szfmt;
286 switch (prog_type) {
287 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE_MASTER_RATIO:
288 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE_MASTER_TABLE:
289 prog_data.v1x_master.b_o_c_o_v_enabled = false;
290 for (j = 0; j < header.vf_entry_count; j++) {
291 memcpy(&vfprog, vfentry, vfszfmt);
292
293 vfentries[j].vfe_idx = (u8)vfprog.vfe_idx;
294 if (CTRL_CLK_PROG_1X_SOURCE_FLL ==
295 prog_data.v1x.source) {
296 vfentries[j].gain_vfe_idx = (u8)BIOS_GET_FIELD(
297 vfprog.param0,
298 NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_VF_ENTRY_PARAM0_FLL_GAIN_VFE_IDX);
299 } else {
300 vfentries[j].gain_vfe_idx = CTRL_BOARDOBJ_IDX_INVALID;
301 }
302 vfentry += vfszfmt;
303 }
304
305 prog_data.v1x_master.p_vf_entries = vfentries;
306
307 for (j = 0; j < header.slave_entry_count; j++) {
308 memcpy(&slaveprog, slaveentry, slaveszfmt);
309
310 switch (prog_type) {
311 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE_MASTER_RATIO:
312 ratioslaveentries[j].clk_dom_idx =
313 (u8)slaveprog.clk_dom_idx;
314 ratioslaveentries[j].ratio = (u8)
315 BIOS_GET_FIELD(slaveprog.param0,
316 NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_SLAVE_ENTRY_PARAM0_MASTER_RATIO_RATIO);
317 break;
318
319 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE_MASTER_TABLE:
320 tableslaveentries[j].clk_dom_idx =
321 (u8)slaveprog.clk_dom_idx;
322 tableslaveentries[j].freq_mhz =
323 (u16)BIOS_GET_FIELD(slaveprog.param0,
324 NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_SLAVE_ENTRY_PARAM0_MASTER_TABLE_FREQ);
325 break;
326 }
327 slaveentry += slaveszfmt;
328 }
329
330 switch (prog_type) {
331 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE_MASTER_RATIO:
332 prog_data.board_obj.type = CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_RATIO;
333 prog_data.v1x_master_ratio.p_slave_entries =
334 ratioslaveentries;
335 break;
336
337 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE_MASTER_TABLE:
338 prog_data.board_obj.type = CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_TABLE;
339
340 prog_data.v1x_master_table.p_slave_entries =
341 tableslaveentries;
342 break;
343
344 }
345 break;
346
347 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE_SLAVE:
348 prog_data.board_obj.type = CTRL_CLK_CLK_PROG_TYPE_1X;
349 break;
350
351
352 default:
353 nvgpu_err(g, "source issue %d", prog_type);
354 status = -EINVAL;
355 goto done;
356 }
357
358 pprog = construct_clk_prog(g, (void *)&prog_data);
359 if (pprog == NULL) {
360 nvgpu_err(g,
361 "error constructing clk_prog boardobj %d", i);
362 status = -EINVAL;
363 goto done;
364 }
365
366 status = boardobjgrp_objinsert(&pclkprogobjs->super.super,
367 (struct boardobj *)pprog, i);
368 if (status) {
369 nvgpu_err(g, "error adding clk_prog boardobj %d", i);
370 status = -EINVAL;
371 goto done;
372 }
373 }
374done:
375 gk20a_dbg_info(" done status %x", status);
376 return status;
377}
378
379static u32 _clk_prog_pmudatainit_super(struct gk20a *g,
380 struct boardobj *board_obj_ptr,
381 struct nv_pmu_boardobj *ppmudata)
382{
383 u32 status = 0;
384
385 gk20a_dbg_info("");
386
387 status = boardobj_pmudatainit_super(g, board_obj_ptr, ppmudata);
388 return status;
389}
390
391static u32 _clk_prog_pmudatainit_1x(struct gk20a *g,
392 struct boardobj *board_obj_ptr,
393 struct nv_pmu_boardobj *ppmudata)
394{
395 u32 status = 0;
396 struct clk_prog_1x *pclk_prog_1x;
397 struct nv_pmu_clk_clk_prog_1x_boardobj_set *pset;
398
399 gk20a_dbg_info("");
400
401 status = _clk_prog_pmudatainit_super(g, board_obj_ptr, ppmudata);
402 if (status != 0)
403 return status;
404
405 pclk_prog_1x = (struct clk_prog_1x *)board_obj_ptr;
406
407 pset = (struct nv_pmu_clk_clk_prog_1x_boardobj_set *)
408 ppmudata;
409
410 pset->source = pclk_prog_1x->source;
411 pset->freq_max_mhz = pclk_prog_1x->freq_max_mhz;
412 pset->source_data = pclk_prog_1x->source_data;
413
414 return status;
415}
416
417static u32 _clk_prog_pmudatainit_1x_master(struct gk20a *g,
418 struct boardobj *board_obj_ptr,
419 struct nv_pmu_boardobj *ppmudata)
420{
421 u32 status = 0;
422 struct clk_prog_1x_master *pclk_prog_1x_master;
423 struct nv_pmu_clk_clk_prog_1x_master_boardobj_set *pset;
424 u32 vfsize = sizeof(struct ctrl_clk_clk_prog_1x_master_vf_entry) *
425 g->clk_pmu.clk_progobjs.vf_entry_count;
426
427 gk20a_dbg_info("");
428
429 status = _clk_prog_pmudatainit_1x(g, board_obj_ptr, ppmudata);
430
431 pclk_prog_1x_master =
432 (struct clk_prog_1x_master *)board_obj_ptr;
433
434 pset = (struct nv_pmu_clk_clk_prog_1x_master_boardobj_set *)
435 ppmudata;
436
437 memcpy(pset->vf_entries, pclk_prog_1x_master->p_vf_entries, vfsize);
438
439 pset->b_o_c_o_v_enabled = pclk_prog_1x_master->b_o_c_o_v_enabled;
440 pset->source_data = pclk_prog_1x_master->source_data;
441
442 memcpy(&pset->deltas, &pclk_prog_1x_master->deltas,
443 (u32) sizeof(struct ctrl_clk_clk_delta));
444
445 return status;
446}
447
448static u32 _clk_prog_pmudatainit_1x_master_ratio(struct gk20a *g,
449 struct boardobj *board_obj_ptr,
450 struct nv_pmu_boardobj *ppmudata)
451{
452 u32 status = 0;
453 struct clk_prog_1x_master_ratio *pclk_prog_1x_master_ratio;
454 struct nv_pmu_clk_clk_prog_1x_master_ratio_boardobj_set *pset;
455 u32 slavesize = sizeof(struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry) *
456 g->clk_pmu.clk_progobjs.slave_entry_count;
457
458 gk20a_dbg_info("");
459
460 status = _clk_prog_pmudatainit_1x_master(g, board_obj_ptr, ppmudata);
461 if (status != 0)
462 return status;
463
464 pclk_prog_1x_master_ratio =
465 (struct clk_prog_1x_master_ratio *)board_obj_ptr;
466
467 pset = (struct nv_pmu_clk_clk_prog_1x_master_ratio_boardobj_set *)
468 ppmudata;
469
470 memcpy(pset->slave_entries,
471 pclk_prog_1x_master_ratio->p_slave_entries, slavesize);
472
473 return status;
474}
475
476static u32 _clk_prog_pmudatainit_1x_master_table(struct gk20a *g,
477 struct boardobj *board_obj_ptr,
478 struct nv_pmu_boardobj *ppmudata)
479{
480 u32 status = 0;
481 struct clk_prog_1x_master_table *pclk_prog_1x_master_table;
482 struct nv_pmu_clk_clk_prog_1x_master_table_boardobj_set *pset;
483 u32 slavesize = sizeof(struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry) *
484 g->clk_pmu.clk_progobjs.slave_entry_count;
485
486 gk20a_dbg_info("");
487
488 status = _clk_prog_pmudatainit_1x_master(g, board_obj_ptr, ppmudata);
489 if (status != 0)
490 return status;
491
492 pclk_prog_1x_master_table =
493 (struct clk_prog_1x_master_table *)board_obj_ptr;
494
495 pset = (struct nv_pmu_clk_clk_prog_1x_master_table_boardobj_set *)
496 ppmudata;
497 memcpy(pset->slave_entries,
498 pclk_prog_1x_master_table->p_slave_entries, slavesize);
499
500 return status;
501}
502
503static u32 _clk_prog_1x_master_rail_construct_vf_point(struct gk20a *g,
504 struct clk_pmupstate *pclk,
505 struct clk_prog_1x_master *p1xmaster,
506 struct ctrl_clk_clk_prog_1x_master_vf_entry *p_vf_rail,
507 struct clk_vf_point *p_vf_point_tmp,
508 u8 *p_vf_point_idx)
509{
510 struct clk_vf_point *p_vf_point;
511 u32 status;
512
513 gk20a_dbg_info("");
514
515 p_vf_point = construct_clk_vf_point(g, (void *)p_vf_point_tmp);
516 if (p_vf_point == NULL) {
517 status = -ENOMEM;
518 goto done;
519 }
520 status = pclk->clk_vf_pointobjs.super.super.objinsert(
521 &pclk->clk_vf_pointobjs.super.super,
522 &p_vf_point->super,
523 *p_vf_point_idx);
524 if (status)
525 goto done;
526
527 p_vf_rail->vf_point_idx_last = (*p_vf_point_idx)++;
528
529done:
530 gk20a_dbg_info("done status %x", status);
531 return status;
532}
533
534static u32 clk_prog_construct_super(struct gk20a *g,
535 struct boardobj **ppboardobj,
536 u16 size, void *pargs)
537{
538 struct clk_prog *pclkprog;
539 u32 status = 0;
540
541 status = boardobj_construct_super(g, ppboardobj,
542 size, pargs);
543 if (status)
544 return -EINVAL;
545
546 pclkprog = (struct clk_prog *)*ppboardobj;
547
548 pclkprog->super.pmudatainit =
549 _clk_prog_pmudatainit_super;
550 return status;
551}
552
553
554static u32 clk_prog_construct_1x(struct gk20a *g,
555 struct boardobj **ppboardobj,
556 u16 size, void *pargs)
557{
558 struct boardobj *ptmpobj = (struct boardobj *)pargs;
559 struct clk_prog_1x *pclkprog;
560 struct clk_prog_1x *ptmpprog =
561 (struct clk_prog_1x *)pargs;
562 u32 status = 0;
563
564 gk20a_dbg_info(" ");
565 ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_PROG_TYPE_1X);
566 status = clk_prog_construct_super(g, ppboardobj, size, pargs);
567 if (status)
568 return -EINVAL;
569
570 pclkprog = (struct clk_prog_1x *)*ppboardobj;
571
572 pclkprog->super.super.pmudatainit =
573 _clk_prog_pmudatainit_1x;
574
575 pclkprog->source = ptmpprog->source;
576 pclkprog->freq_max_mhz = ptmpprog->freq_max_mhz;
577 pclkprog->source_data = ptmpprog->source_data;
578
579 return status;
580}
581
582static u32 clk_prog_construct_1x_master(struct gk20a *g,
583 struct boardobj **ppboardobj,
584 u16 size, void *pargs)
585{
586 struct boardobj *ptmpobj = (struct boardobj *)pargs;
587 struct clk_prog_1x_master *pclkprog;
588 struct clk_prog_1x_master *ptmpprog =
589 (struct clk_prog_1x_master *)pargs;
590 u32 status = 0;
591 u32 vfsize = sizeof(struct ctrl_clk_clk_prog_1x_master_vf_entry) *
592 g->clk_pmu.clk_progobjs.vf_entry_count;
593 u8 railidx;
594
595 gk20a_dbg_info(" type - %x", BOARDOBJ_GET_TYPE(pargs));
596
597 ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_PROG_TYPE_1X_MASTER);
598 status = clk_prog_construct_1x(g, ppboardobj, size, pargs);
599 if (status)
600 return -EINVAL;
601
602 pclkprog = (struct clk_prog_1x_master *)*ppboardobj;
603
604 pclkprog->super.super.super.pmudatainit =
605 _clk_prog_pmudatainit_1x_master;
606
607 pclkprog->vfflatten =
608 vfflatten_prog_1x_master;
609
610 pclkprog->vflookup =
611 vflookup_prog_1x_master;
612
613 pclkprog->getfpoints =
614 getfpoints_prog_1x_master;
615
616 pclkprog->getslaveclk =
617 getslaveclk_prog_1x_master;
618
619 pclkprog->p_vf_entries = (struct ctrl_clk_clk_prog_1x_master_vf_entry *)
620 nvgpu_kzalloc(g, vfsize);
621
622 memcpy(pclkprog->p_vf_entries, ptmpprog->p_vf_entries, vfsize);
623
624 pclkprog->b_o_c_o_v_enabled = ptmpprog->b_o_c_o_v_enabled;
625
626 for (railidx = 0;
627 railidx < g->clk_pmu.clk_progobjs.vf_entry_count;
628 railidx++) {
629 pclkprog->p_vf_entries[railidx].vf_point_idx_first =
630 CTRL_CLK_CLK_VF_POINT_IDX_INVALID;
631 pclkprog->p_vf_entries[railidx].vf_point_idx_last =
632 CTRL_CLK_CLK_VF_POINT_IDX_INVALID;
633 }
634
635 return status;
636}
637
638static u32 clk_prog_construct_1x_master_ratio(struct gk20a *g,
639 struct boardobj **ppboardobj,
640 u16 size, void *pargs)
641{
642 struct boardobj *ptmpobj = (struct boardobj *)pargs;
643 struct clk_prog_1x_master_ratio *pclkprog;
644 struct clk_prog_1x_master_ratio *ptmpprog =
645 (struct clk_prog_1x_master_ratio *)pargs;
646 u32 status = 0;
647 u32 slavesize = sizeof(struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry) *
648 g->clk_pmu.clk_progobjs.slave_entry_count;
649
650 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_RATIO)
651 return -EINVAL;
652
653 ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_RATIO);
654 status = clk_prog_construct_1x_master(g, ppboardobj, size, pargs);
655 if (status)
656 return -EINVAL;
657
658 pclkprog = (struct clk_prog_1x_master_ratio *)*ppboardobj;
659
660 pclkprog->super.super.super.super.pmudatainit =
661 _clk_prog_pmudatainit_1x_master_ratio;
662
663 pclkprog->p_slave_entries =
664 (struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry *)
665 nvgpu_kzalloc(g, slavesize);
666 if (!pclkprog->p_slave_entries)
667 return -ENOMEM;
668
669 memset(pclkprog->p_slave_entries, CTRL_CLK_CLK_DOMAIN_INDEX_INVALID,
670 slavesize);
671
672 memcpy(pclkprog->p_slave_entries, ptmpprog->p_slave_entries, slavesize);
673
674 return status;
675}
676
677static u32 clk_prog_construct_1x_master_table(struct gk20a *g,
678 struct boardobj **ppboardobj,
679 u16 size, void *pargs)
680{
681 struct boardobj *ptmpobj = (struct boardobj *)pargs;
682 struct clk_prog_1x_master_table *pclkprog;
683 struct clk_prog_1x_master_table *ptmpprog =
684 (struct clk_prog_1x_master_table *)pargs;
685 u32 status = 0;
686 u32 slavesize = sizeof(struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry) *
687 g->clk_pmu.clk_progobjs.slave_entry_count;
688
689 gk20a_dbg_info("type - %x", BOARDOBJ_GET_TYPE(pargs));
690
691 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_TABLE)
692 return -EINVAL;
693
694 ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_TABLE);
695 status = clk_prog_construct_1x_master(g, ppboardobj, size, pargs);
696 if (status)
697 return -EINVAL;
698
699 pclkprog = (struct clk_prog_1x_master_table *)*ppboardobj;
700
701 pclkprog->super.super.super.super.pmudatainit =
702 _clk_prog_pmudatainit_1x_master_table;
703
704 pclkprog->p_slave_entries =
705 (struct ctrl_clk_clk_prog_1x_master_table_slave_entry *)
706 nvgpu_kzalloc(g, slavesize);
707
708 if (!pclkprog->p_slave_entries) {
709 status = -ENOMEM;
710 goto exit;
711 }
712
713 memset(pclkprog->p_slave_entries, CTRL_CLK_CLK_DOMAIN_INDEX_INVALID,
714 slavesize);
715
716 memcpy(pclkprog->p_slave_entries, ptmpprog->p_slave_entries, slavesize);
717
718exit:
719 if (status)
720 (*ppboardobj)->destruct(*ppboardobj);
721
722 return status;
723}
724
725static struct clk_prog *construct_clk_prog(struct gk20a *g, void *pargs)
726{
727 struct boardobj *board_obj_ptr = NULL;
728 u32 status;
729
730 gk20a_dbg_info(" type - %x", BOARDOBJ_GET_TYPE(pargs));
731 switch (BOARDOBJ_GET_TYPE(pargs)) {
732 case CTRL_CLK_CLK_PROG_TYPE_1X:
733 status = clk_prog_construct_1x(g, &board_obj_ptr,
734 sizeof(struct clk_prog_1x), pargs);
735 break;
736
737 case CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_TABLE:
738 status = clk_prog_construct_1x_master_table(g, &board_obj_ptr,
739 sizeof(struct clk_prog_1x_master_table), pargs);
740 break;
741
742 case CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_RATIO:
743 status = clk_prog_construct_1x_master_ratio(g, &board_obj_ptr,
744 sizeof(struct clk_prog_1x_master_ratio), pargs);
745 break;
746
747 default:
748 return NULL;
749 }
750
751 if (status) {
752 if (board_obj_ptr)
753 board_obj_ptr->destruct(board_obj_ptr);
754 return NULL;
755 }
756
757 gk20a_dbg_info(" Done");
758
759 return (struct clk_prog *)board_obj_ptr;
760}
761
762static u32 vfflatten_prog_1x_master(struct gk20a *g,
763 struct clk_pmupstate *pclk,
764 struct clk_prog_1x_master *p1xmaster,
765 u8 clk_domain_idx, u16 *pfreqmaxlastmhz)
766{
767 struct ctrl_clk_clk_prog_1x_master_vf_entry *p_vf_rail;
768 union {
769 struct boardobj board_obj;
770 struct clk_vf_point vf_point;
771 struct clk_vf_point_freq freq;
772 struct clk_vf_point_volt volt;
773 } vf_point_data;
774 u32 status = 0;
775 u8 step_count;
776 u8 freq_step_size_mhz = 0;
777 u8 vf_point_idx;
778 u8 vf_rail_idx;
779
780 gk20a_dbg_info("");
781 memset(&vf_point_data, 0x0, sizeof(vf_point_data));
782
783 vf_point_idx = BOARDOBJGRP_NEXT_EMPTY_IDX(
784 &pclk->clk_vf_pointobjs.super.super);
785
786 for (vf_rail_idx = 0;
787 vf_rail_idx < pclk->clk_progobjs.vf_entry_count;
788 vf_rail_idx++) {
789 u32 voltage_min_uv;
790 u32 voltage_step_size_uv;
791 u8 i;
792
793 p_vf_rail = &p1xmaster->p_vf_entries[vf_rail_idx];
794 if (p_vf_rail->vfe_idx == CTRL_BOARDOBJ_IDX_INVALID)
795 continue;
796
797 p_vf_rail->vf_point_idx_first = vf_point_idx;
798
799 vf_point_data.vf_point.vfe_equ_idx = p_vf_rail->vfe_idx;
800 vf_point_data.vf_point.volt_rail_idx = vf_rail_idx;
801
802 step_count = 0;
803
804 switch (p1xmaster->super.source) {
805 case CTRL_CLK_PROG_1X_SOURCE_PLL:
806 freq_step_size_mhz =
807 p1xmaster->super.source_data.pll.freq_step_size_mhz;
808 step_count = (freq_step_size_mhz == 0) ? 0 :
809 (p1xmaster->super.freq_max_mhz - *pfreqmaxlastmhz - 1) /
810 freq_step_size_mhz;
811 /* Intentional fall-through.*/
812
813 case CTRL_CLK_PROG_1X_SOURCE_ONE_SOURCE:
814 vf_point_data.board_obj.type =
815 CTRL_CLK_CLK_VF_POINT_TYPE_FREQ;
816 do {
817 clkvfpointfreqmhzset(g, &vf_point_data.vf_point,
818 p1xmaster->super.freq_max_mhz -
819 step_count * freq_step_size_mhz);
820
821 status = _clk_prog_1x_master_rail_construct_vf_point(g, pclk,
822 p1xmaster, p_vf_rail,
823 &vf_point_data.vf_point, &vf_point_idx);
824 if (status)
825 goto done;
826 } while (step_count-- > 0);
827 break;
828
829 case CTRL_CLK_PROG_1X_SOURCE_FLL:
830 voltage_min_uv = CLK_FLL_LUT_MIN_VOLTAGE_UV(pclk);
831 voltage_step_size_uv = CLK_FLL_LUT_STEP_SIZE_UV(pclk);
832 step_count = CLK_FLL_LUT_VF_NUM_ENTRIES(pclk);
833
834 /* FLL sources use a voltage-based VF_POINT.*/
835 vf_point_data.board_obj.type =
836 CTRL_CLK_CLK_VF_POINT_TYPE_VOLT;
837 for (i = 0; i < step_count; i++) {
838 vf_point_data.volt.source_voltage_uv =
839 voltage_min_uv + i * voltage_step_size_uv;
840
841 status = _clk_prog_1x_master_rail_construct_vf_point(g, pclk,
842 p1xmaster, p_vf_rail,
843 &vf_point_data.vf_point, &vf_point_idx);
844 if (status)
845 goto done;
846 }
847 break;
848 }
849 }
850
851 *pfreqmaxlastmhz = p1xmaster->super.freq_max_mhz;
852
853done:
854 gk20a_dbg_info("done status %x", status);
855 return status;
856}
857
858static u32 vflookup_prog_1x_master
859(
860 struct gk20a *g,
861 struct clk_pmupstate *pclk,
862 struct clk_prog_1x_master *p1xmaster,
863 u8 *slave_clk_domain,
864 u16 *pclkmhz,
865 u32 *pvoltuv,
866 u8 rail
867)
868{
869 int j;
870 struct ctrl_clk_clk_prog_1x_master_vf_entry
871 *pvfentry;
872 struct clk_vf_point *pvfpoint;
873 struct clk_progs *pclkprogobjs;
874 struct clk_prog_1x_master_ratio *p1xmasterratio;
875 u16 clkmhz;
876 u32 voltuv;
877 u8 slaveentrycount;
878 int i;
879 struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry *pslaveents;
880
881 if ((*pclkmhz != 0) && (*pvoltuv != 0))
882 return -EINVAL;
883
884 pclkprogobjs = &(pclk->clk_progobjs);
885
886 slaveentrycount = pclkprogobjs->slave_entry_count;
887
888 if (pclkprogobjs->vf_entry_count >
889 CTRL_CLK_CLK_PROG_1X_MASTER_VF_ENTRY_MAX_ENTRIES)
890 return -EINVAL;
891
892 if (rail >= pclkprogobjs->vf_entry_count)
893 return -EINVAL;
894
895 pvfentry = p1xmaster->p_vf_entries;
896
897 pvfentry = (struct ctrl_clk_clk_prog_1x_master_vf_entry *)(
898 (u8 *)pvfentry +
899 (sizeof(struct ctrl_clk_clk_prog_1x_master_vf_entry) *
900 rail));
901
902 clkmhz = *pclkmhz;
903 voltuv = *pvoltuv;
904
905 /*if domain is slave domain and freq is input
906 then derive master clk */
907 if ((slave_clk_domain != NULL) && (*pclkmhz != 0)) {
908 if (p1xmaster->super.super.super.implements(g,
909 &p1xmaster->super.super.super,
910 CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_RATIO)) {
911
912 p1xmasterratio =
913 (struct clk_prog_1x_master_ratio *)p1xmaster;
914 pslaveents = p1xmasterratio->p_slave_entries;
915 for (i = 0; i < slaveentrycount; i++) {
916 if (pslaveents->clk_dom_idx ==
917 *slave_clk_domain)
918 break;
919 pslaveents++;
920 }
921 if (i == slaveentrycount)
922 return -EINVAL;
923 clkmhz = (clkmhz * 100)/pslaveents->ratio;
924 } else {
925 /* only support ratio for now */
926 return -EINVAL;
927 }
928 }
929
930 /* if both volt and clks are zero simply print*/
931 if ((*pvoltuv == 0) && (*pclkmhz == 0)) {
932 for (j = pvfentry->vf_point_idx_first;
933 j <= pvfentry->vf_point_idx_last; j++) {
934 pvfpoint = CLK_CLK_VF_POINT_GET(pclk, j);
935 nvgpu_err(g, "v %x c %x",
936 clkvfpointvoltageuvget(g, pvfpoint),
937 clkvfpointfreqmhzget(g, pvfpoint));
938 }
939 return -EINVAL;
940 }
941 /* start looking up f for v for v for f */
942 /* looking for volt? */
943 if (*pvoltuv == 0) {
944 pvfpoint = CLK_CLK_VF_POINT_GET(pclk,
945 pvfentry->vf_point_idx_last);
946 /* above range? */
947 if (clkmhz > clkvfpointfreqmhzget(g, pvfpoint))
948 return -EINVAL;
949
950 for (j = pvfentry->vf_point_idx_last;
951 j >= pvfentry->vf_point_idx_first; j--) {
952 pvfpoint = CLK_CLK_VF_POINT_GET(pclk, j);
953 if (clkmhz <= clkvfpointfreqmhzget(g, pvfpoint))
954 voltuv = clkvfpointvoltageuvget(g, pvfpoint);
955 else
956 break;
957 }
958 } else { /* looking for clk? */
959
960 pvfpoint = CLK_CLK_VF_POINT_GET(pclk,
961 pvfentry->vf_point_idx_first);
962 /* below range? */
963 if (voltuv < clkvfpointvoltageuvget(g, pvfpoint))
964 return -EINVAL;
965
966 for (j = pvfentry->vf_point_idx_first;
967 j <= pvfentry->vf_point_idx_last; j++) {
968 pvfpoint = CLK_CLK_VF_POINT_GET(pclk, j);
969 if (voltuv >= clkvfpointvoltageuvget(g, pvfpoint))
970 clkmhz = clkvfpointfreqmhzget(g, pvfpoint);
971 else
972 break;
973 }
974 }
975
976 /*if domain is slave domain and freq was looked up
977 then derive slave clk */
978 if ((slave_clk_domain != NULL) && (*pclkmhz == 0)) {
979 if (p1xmaster->super.super.super.implements(g,
980 &p1xmaster->super.super.super,
981 CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_RATIO)) {
982
983 p1xmasterratio =
984 (struct clk_prog_1x_master_ratio *)p1xmaster;
985 pslaveents = p1xmasterratio->p_slave_entries;
986 for (i = 0; i < slaveentrycount; i++) {
987 if (pslaveents->clk_dom_idx ==
988 *slave_clk_domain)
989 break;
990 pslaveents++;
991 }
992 if (i == slaveentrycount)
993 return -EINVAL;
994 clkmhz = (clkmhz * pslaveents->ratio)/100;
995 } else {
996 /* only support ratio for now */
997 return -EINVAL;
998 }
999 }
1000 *pclkmhz = clkmhz;
1001 *pvoltuv = voltuv;
1002 if ((clkmhz == 0) || (voltuv == 0))
1003 return -EINVAL;
1004 return 0;
1005}
1006
1007static u32 getfpoints_prog_1x_master
1008(
1009 struct gk20a *g,
1010 struct clk_pmupstate *pclk,
1011 struct clk_prog_1x_master *p1xmaster,
1012 u32 *pfpointscount,
1013 u16 **ppfreqpointsinmhz,
1014 u8 rail
1015)
1016{
1017
1018 struct ctrl_clk_clk_prog_1x_master_vf_entry
1019 *pvfentry;
1020 struct clk_vf_point *pvfpoint;
1021 struct clk_progs *pclkprogobjs;
1022 u8 j;
1023 u32 fpointscount = 0;
1024
1025 if (pfpointscount == NULL)
1026 return -EINVAL;
1027
1028 pclkprogobjs = &(pclk->clk_progobjs);
1029
1030 if (pclkprogobjs->vf_entry_count >
1031 CTRL_CLK_CLK_PROG_1X_MASTER_VF_ENTRY_MAX_ENTRIES)
1032 return -EINVAL;
1033
1034 if (rail >= pclkprogobjs->vf_entry_count)
1035 return -EINVAL;
1036
1037 pvfentry = p1xmaster->p_vf_entries;
1038
1039 pvfentry = (struct ctrl_clk_clk_prog_1x_master_vf_entry *)(
1040 (u8 *)pvfentry +
1041 (sizeof(struct ctrl_clk_clk_prog_1x_master_vf_entry) *
1042 (rail+1)));
1043
1044 fpointscount = pvfentry->vf_point_idx_last -
1045 pvfentry->vf_point_idx_first + 1;
1046
1047 /* if pointer for freq data is NULL simply return count */
1048 if (*ppfreqpointsinmhz == NULL)
1049 goto done;
1050
1051 if (fpointscount > *pfpointscount)
1052 return -ENOMEM;
1053 for (j = pvfentry->vf_point_idx_first;
1054 j <= pvfentry->vf_point_idx_last; j++) {
1055 pvfpoint = CLK_CLK_VF_POINT_GET(pclk, j);
1056 **ppfreqpointsinmhz = clkvfpointfreqmhzget(g, pvfpoint);
1057 (*ppfreqpointsinmhz)++;
1058 }
1059done:
1060 *pfpointscount = fpointscount;
1061 return 0;
1062}
1063
1064static int getslaveclk_prog_1x_master(struct gk20a *g,
1065 struct clk_pmupstate *pclk,
1066 struct clk_prog_1x_master *p1xmaster,
1067 u8 slave_clk_domain,
1068 u16 *pclkmhz,
1069 u16 masterclkmhz
1070)
1071{
1072 struct clk_progs *pclkprogobjs;
1073 struct clk_prog_1x_master_ratio *p1xmasterratio;
1074 u8 slaveentrycount;
1075 u8 i;
1076 struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry *pslaveents;
1077
1078 if (pclkmhz == NULL)
1079 return -EINVAL;
1080
1081 if (masterclkmhz == 0)
1082 return -EINVAL;
1083
1084 *pclkmhz = 0;
1085 pclkprogobjs = &(pclk->clk_progobjs);
1086
1087 slaveentrycount = pclkprogobjs->slave_entry_count;
1088
1089 if (p1xmaster->super.super.super.implements(g,
1090 &p1xmaster->super.super.super,
1091 CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_RATIO)) {
1092 p1xmasterratio =
1093 (struct clk_prog_1x_master_ratio *)p1xmaster;
1094 pslaveents = p1xmasterratio->p_slave_entries;
1095 for (i = 0; i < slaveentrycount; i++) {
1096 if (pslaveents->clk_dom_idx ==
1097 slave_clk_domain)
1098 break;
1099 pslaveents++;
1100 }
1101 if (i == slaveentrycount)
1102 return -EINVAL;
1103 *pclkmhz = (masterclkmhz * pslaveents->ratio)/100;
1104 } else {
1105 /* only support ratio for now */
1106 return -EINVAL;
1107 }
1108 return 0;
1109}
diff --git a/drivers/gpu/nvgpu/clk/clk_prog.h b/drivers/gpu/nvgpu/clk/clk_prog.h
new file mode 100644
index 00000000..64cb1b51
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk_prog.h
@@ -0,0 +1,100 @@
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#ifndef _CLKPROG_H_
24#define _CLKPROG_H_
25#include "ctrl/ctrlclk.h"
26#include "ctrl/ctrlboardobj.h"
27#include <nvgpu/pmuif/nvgpu_gpmu_cmdif.h>
28#include "boardobj/boardobjgrp_e32.h"
29#include "boardobj/boardobjgrp_e255.h"
30#include "boardobj/boardobjgrpmask.h"
31
32u32 clk_prog_sw_setup(struct gk20a *g);
33u32 clk_prog_pmu_setup(struct gk20a *g);
34struct clk_prog_1x_master;
35
36typedef u32 vf_flatten(struct gk20a *g, struct clk_pmupstate *pclk,
37 struct clk_prog_1x_master *p1xmaster,
38 u8 clk_domain_idx, u16 *pfreqmaxlastmhz);
39
40typedef u32 vf_lookup(struct gk20a *g, struct clk_pmupstate *pclk,
41 struct clk_prog_1x_master *p1xmaster,
42 u8 *slave_clk_domain_idx, u16 *pclkmhz,
43 u32 *pvoltuv, u8 rail);
44
45typedef int get_slaveclk(struct gk20a *g, struct clk_pmupstate *pclk,
46 struct clk_prog_1x_master *p1xmaster,
47 u8 slave_clk_domain_idx, u16 *pclkmhz,
48 u16 masterclkmhz);
49
50typedef u32 get_fpoints(struct gk20a *g, struct clk_pmupstate *pclk,
51 struct clk_prog_1x_master *p1xmaster,
52 u32 *pfpointscount,
53 u16 **ppfreqpointsinmhz, u8 rail);
54
55
56struct clk_progs {
57 struct boardobjgrp_e255 super;
58 u8 slave_entry_count;
59 u8 vf_entry_count;
60
61};
62
63struct clk_prog {
64 struct boardobj super;
65};
66
67struct clk_prog_1x {
68 struct clk_prog super;
69 u8 source;
70 u16 freq_max_mhz;
71 union ctrl_clk_clk_prog_1x_source_data source_data;
72};
73
74struct clk_prog_1x_master {
75 struct clk_prog_1x super;
76 bool b_o_c_o_v_enabled;
77 struct ctrl_clk_clk_prog_1x_master_vf_entry *p_vf_entries;
78 struct ctrl_clk_clk_delta deltas;
79 union ctrl_clk_clk_prog_1x_master_source_data source_data;
80 vf_flatten *vfflatten;
81 vf_lookup *vflookup;
82 get_fpoints *getfpoints;
83 get_slaveclk *getslaveclk;
84};
85
86struct clk_prog_1x_master_ratio {
87 struct clk_prog_1x_master super;
88 struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry *p_slave_entries;
89};
90
91struct clk_prog_1x_master_table {
92 struct clk_prog_1x_master super;
93 struct ctrl_clk_clk_prog_1x_master_table_slave_entry *p_slave_entries;
94};
95
96#define CLK_CLK_PROG_GET(pclk, idx) \
97 ((struct clk_prog *)BOARDOBJGRP_OBJ_GET_BY_IDX( \
98 &pclk->clk_progobjs.super.super, (u8)(idx)))
99
100#endif
diff --git a/drivers/gpu/nvgpu/clk/clk_vf_point.c b/drivers/gpu/nvgpu/clk/clk_vf_point.c
new file mode 100644
index 00000000..49327698
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk_vf_point.c
@@ -0,0 +1,421 @@
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
24#include "gk20a/gk20a.h"
25#include "clk.h"
26#include "clk_vf_point.h"
27#include "boardobj/boardobjgrp.h"
28#include "boardobj/boardobjgrp_e32.h"
29#include "ctrl/ctrlclk.h"
30#include "ctrl/ctrlvolt.h"
31
32static u32 _clk_vf_point_pmudatainit_super(struct gk20a *g, struct boardobj
33 *board_obj_ptr, struct nv_pmu_boardobj *ppmudata);
34
35static u32 _clk_vf_points_pmudatainit(struct gk20a *g,
36 struct boardobjgrp *pboardobjgrp,
37 struct nv_pmu_boardobjgrp_super *pboardobjgrppmu)
38{
39 u32 status = 0;
40
41 status = boardobjgrp_pmudatainit_e32(g, pboardobjgrp, pboardobjgrppmu);
42 if (status) {
43 nvgpu_err(g,
44 "error updating pmu boardobjgrp for clk vfpoint 0x%x",
45 status);
46 goto done;
47 }
48
49done:
50 return status;
51}
52
53static u32 _clk_vf_points_pmudata_instget(struct gk20a *g,
54 struct nv_pmu_boardobjgrp *pmuboardobjgrp,
55 struct nv_pmu_boardobj **ppboardobjpmudata,
56 u8 idx)
57{
58 struct nv_pmu_clk_clk_vf_point_boardobj_grp_set *pgrp_set =
59 (struct nv_pmu_clk_clk_vf_point_boardobj_grp_set *)
60 pmuboardobjgrp;
61
62 gk20a_dbg_info("");
63
64 /*check whether pmuboardobjgrp has a valid boardobj in index*/
65 if (idx >= CTRL_BOARDOBJGRP_E255_MAX_OBJECTS)
66 return -EINVAL;
67
68 *ppboardobjpmudata = (struct nv_pmu_boardobj *)
69 &pgrp_set->objects[idx].data.board_obj;
70 gk20a_dbg_info(" Done");
71 return 0;
72}
73
74static u32 _clk_vf_points_pmustatus_instget(struct gk20a *g,
75 void *pboardobjgrppmu,
76 struct nv_pmu_boardobj_query **ppboardobjpmustatus,
77 u8 idx)
78{
79 struct nv_pmu_clk_clk_vf_point_boardobj_grp_get_status *pgrp_get_status =
80 (struct nv_pmu_clk_clk_vf_point_boardobj_grp_get_status *)
81 pboardobjgrppmu;
82
83 /*check whether pmuboardobjgrp has a valid boardobj in index*/
84 if (idx >= CTRL_BOARDOBJGRP_E255_MAX_OBJECTS)
85 return -EINVAL;
86
87 *ppboardobjpmustatus = (struct nv_pmu_boardobj_query *)
88 &pgrp_get_status->objects[idx].data.board_obj;
89 return 0;
90}
91
92u32 clk_vf_point_sw_setup(struct gk20a *g)
93{
94 u32 status;
95 struct boardobjgrp *pboardobjgrp = NULL;
96 struct clk_vf_points *pclkvfpointobjs;
97
98 gk20a_dbg_info("");
99
100 status = boardobjgrpconstruct_e255(g, &g->clk_pmu.clk_vf_pointobjs.super);
101 if (status) {
102 nvgpu_err(g,
103 "error creating boardobjgrp for clk vfpoint, status - 0x%x",
104 status);
105 goto done;
106 }
107
108 pboardobjgrp = &g->clk_pmu.clk_vf_pointobjs.super.super;
109 pclkvfpointobjs = &(g->clk_pmu.clk_vf_pointobjs);
110
111 BOARDOBJGRP_PMU_CONSTRUCT(pboardobjgrp, CLK, CLK_VF_POINT);
112
113 status = BOARDOBJGRP_PMU_CMD_GRP_SET_CONSTRUCT(g, pboardobjgrp,
114 clk, CLK, clk_vf_point, CLK_VF_POINT);
115 if (status) {
116 nvgpu_err(g,
117 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
118 status);
119 goto done;
120 }
121
122 status = BOARDOBJGRP_PMU_CMD_GRP_GET_STATUS_CONSTRUCT(g,
123 &g->clk_pmu.clk_vf_pointobjs.super.super,
124 clk, CLK, clk_vf_point, CLK_VF_POINT);
125 if (status) {
126 nvgpu_err(g,
127 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
128 status);
129 goto done;
130 }
131
132 pboardobjgrp->pmudatainit = _clk_vf_points_pmudatainit;
133 pboardobjgrp->pmudatainstget = _clk_vf_points_pmudata_instget;
134 pboardobjgrp->pmustatusinstget = _clk_vf_points_pmustatus_instget;
135
136done:
137 gk20a_dbg_info(" done status %x", status);
138 return status;
139}
140
141u32 clk_vf_point_pmu_setup(struct gk20a *g)
142{
143 u32 status;
144 struct boardobjgrp *pboardobjgrp = NULL;
145
146 gk20a_dbg_info("");
147
148 pboardobjgrp = &g->clk_pmu.clk_vf_pointobjs.super.super;
149
150 if (!pboardobjgrp->bconstructed)
151 return -EINVAL;
152
153 status = pboardobjgrp->pmuinithandle(g, pboardobjgrp);
154
155 gk20a_dbg_info("Done");
156 return status;
157}
158
159static u32 clk_vf_point_construct_super(struct gk20a *g,
160 struct boardobj **ppboardobj,
161 u16 size, void *pargs)
162{
163 struct clk_vf_point *pclkvfpoint;
164 struct clk_vf_point *ptmpvfpoint =
165 (struct clk_vf_point *)pargs;
166 u32 status = 0;
167
168 status = boardobj_construct_super(g, ppboardobj,
169 size, pargs);
170 if (status)
171 return -EINVAL;
172
173 pclkvfpoint = (struct clk_vf_point *)*ppboardobj;
174
175 pclkvfpoint->super.pmudatainit =
176 _clk_vf_point_pmudatainit_super;
177
178 pclkvfpoint->vfe_equ_idx = ptmpvfpoint->vfe_equ_idx;
179 pclkvfpoint->volt_rail_idx = ptmpvfpoint->volt_rail_idx;
180
181 return status;
182}
183
184static u32 _clk_vf_point_pmudatainit_volt(struct gk20a *g,
185 struct boardobj *board_obj_ptr,
186 struct nv_pmu_boardobj *ppmudata)
187{
188 u32 status = 0;
189 struct clk_vf_point_volt *pclk_vf_point_volt;
190 struct nv_pmu_clk_clk_vf_point_volt_boardobj_set *pset;
191
192 gk20a_dbg_info("");
193
194 status = _clk_vf_point_pmudatainit_super(g, board_obj_ptr, ppmudata);
195 if (status != 0)
196 return status;
197
198 pclk_vf_point_volt =
199 (struct clk_vf_point_volt *)board_obj_ptr;
200
201 pset = (struct nv_pmu_clk_clk_vf_point_volt_boardobj_set *)
202 ppmudata;
203
204 pset->source_voltage_uv = pclk_vf_point_volt->source_voltage_uv;
205 pset->freq_delta_khz = pclk_vf_point_volt->freq_delta_khz;
206
207 return status;
208}
209
210static u32 _clk_vf_point_pmudatainit_freq(struct gk20a *g,
211 struct boardobj *board_obj_ptr,
212 struct nv_pmu_boardobj *ppmudata)
213{
214 u32 status = 0;
215 struct clk_vf_point_freq *pclk_vf_point_freq;
216 struct nv_pmu_clk_clk_vf_point_freq_boardobj_set *pset;
217
218 gk20a_dbg_info("");
219
220 status = _clk_vf_point_pmudatainit_super(g, board_obj_ptr, ppmudata);
221 if (status != 0)
222 return status;
223
224 pclk_vf_point_freq =
225 (struct clk_vf_point_freq *)board_obj_ptr;
226
227 pset = (struct nv_pmu_clk_clk_vf_point_freq_boardobj_set *)
228 ppmudata;
229
230 pset->freq_mhz =
231 clkvfpointfreqmhzget(g, &pclk_vf_point_freq->super);
232
233 pset->volt_delta_uv = pclk_vf_point_freq->volt_delta_uv;
234
235 return status;
236}
237
238static u32 clk_vf_point_construct_volt(struct gk20a *g,
239 struct boardobj **ppboardobj,
240 u16 size, void *pargs)
241{
242 struct boardobj *ptmpobj = (struct boardobj *)pargs;
243 struct clk_vf_point_volt *pclkvfpoint;
244 struct clk_vf_point_volt *ptmpvfpoint =
245 (struct clk_vf_point_volt *)pargs;
246 u32 status = 0;
247
248 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_CLK_CLK_VF_POINT_TYPE_VOLT)
249 return -EINVAL;
250
251 ptmpobj->type_mask = BIT(CTRL_CLK_CLK_VF_POINT_TYPE_VOLT);
252 status = clk_vf_point_construct_super(g, ppboardobj, size, pargs);
253 if (status)
254 return -EINVAL;
255
256 pclkvfpoint = (struct clk_vf_point_volt *)*ppboardobj;
257
258 pclkvfpoint->super.super.pmudatainit =
259 _clk_vf_point_pmudatainit_volt;
260
261 pclkvfpoint->source_voltage_uv = ptmpvfpoint->source_voltage_uv;
262
263 return status;
264}
265
266static u32 clk_vf_point_construct_freq(struct gk20a *g,
267 struct boardobj **ppboardobj,
268 u16 size, void *pargs)
269{
270 struct boardobj *ptmpobj = (struct boardobj *)pargs;
271 struct clk_vf_point_freq *pclkvfpoint;
272 struct clk_vf_point_freq *ptmpvfpoint =
273 (struct clk_vf_point_freq *)pargs;
274 u32 status = 0;
275
276 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_CLK_CLK_VF_POINT_TYPE_FREQ)
277 return -EINVAL;
278
279 ptmpobj->type_mask = BIT(CTRL_CLK_CLK_VF_POINT_TYPE_FREQ);
280 status = clk_vf_point_construct_super(g, ppboardobj, size, pargs);
281 if (status)
282 return -EINVAL;
283
284 pclkvfpoint = (struct clk_vf_point_freq *)*ppboardobj;
285
286 pclkvfpoint->super.super.pmudatainit =
287 _clk_vf_point_pmudatainit_freq;
288
289 clkvfpointfreqmhzset(g, &pclkvfpoint->super,
290 clkvfpointfreqmhzget(g, &ptmpvfpoint->super));
291
292 return status;
293}
294
295struct clk_vf_point *construct_clk_vf_point(struct gk20a *g, void *pargs)
296{
297 struct boardobj *board_obj_ptr = NULL;
298 u32 status;
299
300 gk20a_dbg_info("");
301 switch (BOARDOBJ_GET_TYPE(pargs)) {
302 case CTRL_CLK_CLK_VF_POINT_TYPE_FREQ:
303 status = clk_vf_point_construct_freq(g, &board_obj_ptr,
304 sizeof(struct clk_vf_point_freq), pargs);
305 break;
306
307 case CTRL_CLK_CLK_VF_POINT_TYPE_VOLT:
308 status = clk_vf_point_construct_volt(g, &board_obj_ptr,
309 sizeof(struct clk_vf_point_volt), pargs);
310 break;
311
312 default:
313 return NULL;
314 }
315
316 if (status)
317 return NULL;
318
319 gk20a_dbg_info(" Done");
320
321 return (struct clk_vf_point *)board_obj_ptr;
322}
323
324static u32 _clk_vf_point_pmudatainit_super(struct gk20a *g,
325 struct boardobj *board_obj_ptr,
326 struct nv_pmu_boardobj *ppmudata)
327{
328 u32 status = 0;
329 struct clk_vf_point *pclk_vf_point;
330 struct nv_pmu_clk_clk_vf_point_boardobj_set *pset;
331
332 gk20a_dbg_info("");
333
334 status = boardobj_pmudatainit_super(g, board_obj_ptr, ppmudata);
335 if (status != 0)
336 return status;
337
338 pclk_vf_point =
339 (struct clk_vf_point *)board_obj_ptr;
340
341 pset = (struct nv_pmu_clk_clk_vf_point_boardobj_set *)
342 ppmudata;
343
344
345 pset->vfe_equ_idx = pclk_vf_point->vfe_equ_idx;
346 pset->volt_rail_idx = pclk_vf_point->volt_rail_idx;
347 return status;
348}
349
350
351static u32 clk_vf_point_update(struct gk20a *g,
352 struct boardobj *board_obj_ptr,
353 struct nv_pmu_boardobj *ppmudata)
354{
355 struct clk_vf_point *pclk_vf_point;
356 struct nv_pmu_clk_clk_vf_point_boardobj_get_status *pstatus;
357
358 gk20a_dbg_info("");
359
360
361 pclk_vf_point =
362 (struct clk_vf_point *)board_obj_ptr;
363
364 pstatus = (struct nv_pmu_clk_clk_vf_point_boardobj_get_status *)
365 ppmudata;
366
367 if (pstatus->super.type != pclk_vf_point->super.type) {
368 nvgpu_err(g,
369 "pmu data and boardobj type not matching");
370 return -EINVAL;
371 }
372 /* now copy VF pair */
373 memcpy(&pclk_vf_point->pair, &pstatus->pair,
374 sizeof(struct ctrl_clk_vf_pair));
375 return 0;
376}
377
378/*get latest vf point data from PMU */
379u32 clk_vf_point_cache(struct gk20a *g)
380{
381
382 struct clk_vf_points *pclk_vf_points;
383 struct boardobjgrp *pboardobjgrp;
384 struct boardobjgrpmask *pboardobjgrpmask;
385 struct nv_pmu_boardobjgrp_super *pboardobjgrppmu;
386 struct boardobj *pboardobj = NULL;
387 struct nv_pmu_boardobj_query *pboardobjpmustatus = NULL;
388 u32 status;
389 u8 index;
390
391 gk20a_dbg_info("");
392 pclk_vf_points = &g->clk_pmu.clk_vf_pointobjs;
393 pboardobjgrp = &pclk_vf_points->super.super;
394 pboardobjgrpmask = &pclk_vf_points->super.mask.super;
395
396 status = pboardobjgrp->pmugetstatus(g, pboardobjgrp, pboardobjgrpmask);
397 if (status) {
398 nvgpu_err(g, "err getting boardobjs from pmu");
399 return status;
400 }
401 pboardobjgrppmu = pboardobjgrp->pmu.getstatus.buf;
402
403 BOARDOBJGRP_FOR_EACH(pboardobjgrp, struct boardobj*, pboardobj, index) {
404 status = pboardobjgrp->pmustatusinstget(g,
405 (struct nv_pmu_boardobjgrp *)pboardobjgrppmu,
406 &pboardobjpmustatus, index);
407 if (status) {
408 nvgpu_err(g, "could not get status object instance");
409 return status;
410 }
411
412 status = clk_vf_point_update(g, pboardobj,
413 (struct nv_pmu_boardobj *)pboardobjpmustatus);
414 if (status) {
415 nvgpu_err(g, "invalid data from pmu at %d", index);
416 return status;
417 }
418 }
419
420 return 0;
421}
diff --git a/drivers/gpu/nvgpu/clk/clk_vf_point.h b/drivers/gpu/nvgpu/clk/clk_vf_point.h
new file mode 100644
index 00000000..9a4eec10
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk_vf_point.h
@@ -0,0 +1,83 @@
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#ifndef _CLKVFPOINT_H_
24#define _CLKVFPOINT_H_
25#include "ctrl/ctrlclk.h"
26#include "ctrl/ctrlboardobj.h"
27#include <nvgpu/pmuif/nvgpu_gpmu_cmdif.h>
28#include "boardobj/boardobjgrp_e32.h"
29#include "boardobj/boardobjgrpmask.h"
30
31u32 clk_vf_point_sw_setup(struct gk20a *g);
32u32 clk_vf_point_pmu_setup(struct gk20a *g);
33u32 clk_vf_point_cache(struct gk20a *g);
34
35struct clk_vf_points {
36 struct boardobjgrp_e255 super;
37};
38
39struct clk_vf_point {
40 struct boardobj super;
41 u8 vfe_equ_idx;
42 u8 volt_rail_idx;
43 struct ctrl_clk_vf_pair pair;
44};
45
46struct clk_vf_point_volt {
47 struct clk_vf_point super;
48 u32 source_voltage_uv;
49 int freq_delta_khz;
50};
51
52struct clk_vf_point_freq {
53 struct clk_vf_point super;
54 int volt_delta_uv;
55};
56
57#define CLK_CLK_VF_POINT_GET(pclk, idx) \
58 ((struct clk_vf_point *)BOARDOBJGRP_OBJ_GET_BY_IDX( \
59 &pclk->clk_vf_pointobjs.super.super, (u8)(idx)))
60
61#define clkvfpointpairget(pvfpoint) \
62 (&((pvfpoint)->pair))
63
64#define clkvfpointfreqmhzget(pgpu, pvfpoint) \
65 CTRL_CLK_VF_PAIR_FREQ_MHZ_GET(clkvfpointpairget(pvfpoint))
66
67#define clkvfpointfreqdeltamhzGet(pgpu, pvfPoint) \
68 ((BOARDOBJ_GET_TYPE(pvfpoint) == CTRL_CLK_CLK_VF_POINT_TYPE_VOLT) ? \
69 (((struct clk_vf_point_volt *)(pvfpoint))->freq_delta_khz / 1000) : 0)
70
71#define clkvfpointfreqmhzset(pgpu, pvfpoint, _freqmhz) \
72 CTRL_CLK_VF_PAIR_FREQ_MHZ_SET(clkvfpointpairget(pvfpoint), _freqmhz)
73
74#define clkvfpointvoltageuvset(pgpu, pvfpoint, _voltageuv) \
75 CTRL_CLK_VF_PAIR_VOLTAGE_UV_SET(clkvfpointpairget(pvfpoint), \
76 _voltageuv)
77
78#define clkvfpointvoltageuvget(pgpu, pvfpoint) \
79 CTRL_CLK_VF_PAIR_VOLTAGE_UV_GET(clkvfpointpairget(pvfpoint)) \
80
81struct clk_vf_point *construct_clk_vf_point(struct gk20a *g, void *pargs);
82
83#endif
diff --git a/drivers/gpu/nvgpu/clk/clk_vin.c b/drivers/gpu/nvgpu/clk/clk_vin.c
new file mode 100644
index 00000000..17e1c15a
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk_vin.c
@@ -0,0 +1,480 @@
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#include <nvgpu/pmuif/nvgpu_gpmu_cmdif.h>
25
26#include "gk20a/gk20a.h"
27
28#include "boardobj/boardobjgrp.h"
29#include "boardobj/boardobjgrp_e32.h"
30
31#include "ctrl/ctrlvolt.h"
32
33#include "gp106/bios_gp106.h"
34
35#include "clk.h"
36#include "clk_vin.h"
37
38#include <nvgpu/hw/gp106/hw_fuse_gp106.h>
39
40static u32 devinit_get_vin_device_table(struct gk20a *g,
41 struct avfsvinobjs *pvinobjs);
42
43static struct vin_device *construct_vin_device(struct gk20a *g, void *pargs);
44
45static u32 vin_device_init_pmudata_super(struct gk20a *g,
46 struct boardobj *board_obj_ptr,
47 struct nv_pmu_boardobj *ppmudata);
48
49static u32 read_vin_cal_fuse_rev(struct gk20a *g)
50{
51 return fuse_vin_cal_fuse_rev_data_v(
52 gk20a_readl(g, fuse_vin_cal_fuse_rev_r()));
53}
54
55static u32 read_vin_cal_slope_intercept_fuse(struct gk20a *g,
56 u32 vin_id, u32 *slope,
57 u32 *intercept)
58{
59 u32 data = 0;
60 u32 interceptdata = 0;
61 u32 slopedata = 0;
62 u32 gpc0data;
63 u32 gpc0slopedata;
64 u32 gpc0interceptdata;
65
66 /* read gpc0 irrespective of vin id */
67 gpc0data = gk20a_readl(g, fuse_vin_cal_gpc0_r());
68 if (gpc0data == 0xFFFFFFFF)
69 return -EINVAL;
70
71 switch (vin_id) {
72 case CTRL_CLK_VIN_ID_GPC0:
73 break;
74
75 case CTRL_CLK_VIN_ID_GPC1:
76 data = gk20a_readl(g, fuse_vin_cal_gpc1_delta_r());
77 break;
78
79 case CTRL_CLK_VIN_ID_GPC2:
80 data = gk20a_readl(g, fuse_vin_cal_gpc2_delta_r());
81 break;
82
83 case CTRL_CLK_VIN_ID_GPC3:
84 data = gk20a_readl(g, fuse_vin_cal_gpc3_delta_r());
85 break;
86
87 case CTRL_CLK_VIN_ID_GPC4:
88 data = gk20a_readl(g, fuse_vin_cal_gpc4_delta_r());
89 break;
90
91 case CTRL_CLK_VIN_ID_GPC5:
92 data = gk20a_readl(g, fuse_vin_cal_gpc5_delta_r());
93 break;
94
95 case CTRL_CLK_VIN_ID_SYS:
96 case CTRL_CLK_VIN_ID_XBAR:
97 case CTRL_CLK_VIN_ID_LTC:
98 data = gk20a_readl(g, fuse_vin_cal_shared_delta_r());
99 break;
100
101 case CTRL_CLK_VIN_ID_SRAM:
102 data = gk20a_readl(g, fuse_vin_cal_sram_delta_r());
103 break;
104
105 default:
106 return -EINVAL;
107 }
108 if (data == 0xFFFFFFFF)
109 return -EINVAL;
110
111 gpc0interceptdata = (fuse_vin_cal_gpc0_icpt_int_data_v(gpc0data) <<
112 fuse_vin_cal_gpc0_icpt_frac_data_s()) +
113 fuse_vin_cal_gpc0_icpt_frac_data_v(gpc0data);
114 gpc0interceptdata = (gpc0interceptdata * 1000U) >>
115 fuse_vin_cal_gpc0_icpt_frac_data_s();
116
117 switch (vin_id) {
118 case CTRL_CLK_VIN_ID_GPC0:
119 break;
120
121 case CTRL_CLK_VIN_ID_GPC1:
122 case CTRL_CLK_VIN_ID_GPC2:
123 case CTRL_CLK_VIN_ID_GPC3:
124 case CTRL_CLK_VIN_ID_GPC4:
125 case CTRL_CLK_VIN_ID_GPC5:
126 case CTRL_CLK_VIN_ID_SYS:
127 case CTRL_CLK_VIN_ID_XBAR:
128 case CTRL_CLK_VIN_ID_LTC:
129 interceptdata = (fuse_vin_cal_gpc1_delta_icpt_int_data_v(data) <<
130 fuse_vin_cal_gpc1_delta_icpt_frac_data_s()) +
131 fuse_vin_cal_gpc1_delta_icpt_frac_data_v(data);
132 interceptdata = (interceptdata * 1000U) >>
133 fuse_vin_cal_gpc1_delta_icpt_frac_data_s();
134 break;
135
136 case CTRL_CLK_VIN_ID_SRAM:
137 interceptdata = (fuse_vin_cal_sram_delta_icpt_int_data_v(data) <<
138 fuse_vin_cal_sram_delta_icpt_frac_data_s()) +
139 fuse_vin_cal_sram_delta_icpt_frac_data_v(data);
140 interceptdata = (interceptdata * 1000U) >>
141 fuse_vin_cal_sram_delta_icpt_frac_data_s();
142 break;
143
144 default:
145 return -EINVAL;
146 }
147
148 if (fuse_vin_cal_gpc1_delta_icpt_sign_data_v(data))
149 *intercept = gpc0interceptdata - interceptdata;
150 else
151 *intercept = gpc0interceptdata + interceptdata;
152
153 /* slope */
154 gpc0slopedata = (fuse_vin_cal_gpc0_slope_int_data_v(gpc0data) <<
155 fuse_vin_cal_gpc0_slope_frac_data_s()) +
156 fuse_vin_cal_gpc0_slope_frac_data_v(gpc0data);
157 gpc0slopedata = (gpc0slopedata * 1000U) >>
158 fuse_vin_cal_gpc0_slope_frac_data_s();
159 switch (vin_id) {
160 case CTRL_CLK_VIN_ID_GPC0:
161 break;
162
163 case CTRL_CLK_VIN_ID_GPC1:
164 case CTRL_CLK_VIN_ID_GPC2:
165 case CTRL_CLK_VIN_ID_GPC3:
166 case CTRL_CLK_VIN_ID_GPC4:
167 case CTRL_CLK_VIN_ID_GPC5:
168 case CTRL_CLK_VIN_ID_SYS:
169 case CTRL_CLK_VIN_ID_XBAR:
170 case CTRL_CLK_VIN_ID_LTC:
171 case CTRL_CLK_VIN_ID_SRAM:
172 slopedata =
173 (fuse_vin_cal_gpc1_delta_slope_int_data_v(data)) * 1000;
174 break;
175
176 default:
177 return -EINVAL;
178 }
179
180 if (fuse_vin_cal_gpc1_delta_slope_sign_data_v(data))
181 *slope = gpc0slopedata - slopedata;
182 else
183 *slope = gpc0slopedata + slopedata;
184 return 0;
185}
186
187static u32 _clk_vin_devgrp_pmudatainit_super(struct gk20a *g,
188 struct boardobjgrp *pboardobjgrp,
189 struct nv_pmu_boardobjgrp_super *pboardobjgrppmu)
190{
191 struct nv_pmu_clk_clk_vin_device_boardobjgrp_set_header *pset =
192 (struct nv_pmu_clk_clk_vin_device_boardobjgrp_set_header *)
193 pboardobjgrppmu;
194 struct avfsvinobjs *pvin_obbj = (struct avfsvinobjs *)pboardobjgrp;
195 u32 status = 0;
196
197 gk20a_dbg_info("");
198
199 status = boardobjgrp_pmudatainit_e32(g, pboardobjgrp, pboardobjgrppmu);
200
201 pset->b_vin_is_disable_allowed = pvin_obbj->vin_is_disable_allowed;
202
203 gk20a_dbg_info(" Done");
204 return status;
205}
206
207static u32 _clk_vin_devgrp_pmudata_instget(struct gk20a *g,
208 struct nv_pmu_boardobjgrp *pmuboardobjgrp,
209 struct nv_pmu_boardobj **ppboardobjpmudata,
210 u8 idx)
211{
212 struct nv_pmu_clk_clk_vin_device_boardobj_grp_set *pgrp_set =
213 (struct nv_pmu_clk_clk_vin_device_boardobj_grp_set *)
214 pmuboardobjgrp;
215
216 gk20a_dbg_info("");
217
218 /*check whether pmuboardobjgrp has a valid boardobj in index*/
219 if (((u32)BIT(idx) &
220 pgrp_set->hdr.data.super.obj_mask.super.data[0]) == 0)
221 return -EINVAL;
222
223 *ppboardobjpmudata = (struct nv_pmu_boardobj *)
224 &pgrp_set->objects[idx].data.board_obj;
225 gk20a_dbg_info(" Done");
226 return 0;
227}
228
229static u32 _clk_vin_devgrp_pmustatus_instget(struct gk20a *g,
230 void *pboardobjgrppmu,
231 struct nv_pmu_boardobj_query **ppboardobjpmustatus,
232 u8 idx)
233{
234 struct nv_pmu_clk_clk_vin_device_boardobj_grp_get_status *pgrp_get_status =
235 (struct nv_pmu_clk_clk_vin_device_boardobj_grp_get_status *)
236 pboardobjgrppmu;
237
238 /*check whether pmuboardobjgrp has a valid boardobj in index*/
239 if (((u32)BIT(idx) &
240 pgrp_get_status->hdr.data.super.obj_mask.super.data[0]) == 0)
241 return -EINVAL;
242
243 *ppboardobjpmustatus = (struct nv_pmu_boardobj_query *)
244 &pgrp_get_status->objects[idx].data.board_obj;
245 return 0;
246}
247
248u32 clk_vin_sw_setup(struct gk20a *g)
249{
250 u32 status;
251 struct boardobjgrp *pboardobjgrp = NULL;
252 u32 slope;
253 u32 intercept;
254 struct vin_device *pvindev;
255 struct avfsvinobjs *pvinobjs;
256 u8 i;
257
258 gk20a_dbg_info("");
259
260 status = boardobjgrpconstruct_e32(g, &g->clk_pmu.avfs_vinobjs.super);
261 if (status) {
262 nvgpu_err(g,
263 "error creating boardobjgrp for clk vin, statu - 0x%x",
264 status);
265 goto done;
266 }
267
268 pboardobjgrp = &g->clk_pmu.avfs_vinobjs.super.super;
269 pvinobjs = &g->clk_pmu.avfs_vinobjs;
270
271 BOARDOBJGRP_PMU_CONSTRUCT(pboardobjgrp, CLK, VIN_DEVICE);
272
273 status = BOARDOBJGRP_PMU_CMD_GRP_SET_CONSTRUCT(g, pboardobjgrp,
274 clk, CLK, clk_vin_device, CLK_VIN_DEVICE);
275 if (status) {
276 nvgpu_err(g,
277 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
278 status);
279 goto done;
280 }
281
282 pboardobjgrp->pmudatainit = _clk_vin_devgrp_pmudatainit_super;
283 pboardobjgrp->pmudatainstget = _clk_vin_devgrp_pmudata_instget;
284 pboardobjgrp->pmustatusinstget = _clk_vin_devgrp_pmustatus_instget;
285
286 status = devinit_get_vin_device_table(g, &g->clk_pmu.avfs_vinobjs);
287 if (status)
288 goto done;
289
290 /*update vin calibration to fuse */
291 if (pvinobjs->calibration_rev_vbios == read_vin_cal_fuse_rev(g)) {
292 BOARDOBJGRP_FOR_EACH(&(pvinobjs->super.super),
293 struct vin_device *, pvindev, i) {
294 slope = 0;
295 intercept = 0;
296 pvindev = CLK_GET_VIN_DEVICE(pvinobjs, i);
297 status = read_vin_cal_slope_intercept_fuse(g,
298 pvindev->id, &slope, &intercept);
299 if (status) {
300 nvgpu_err(g,
301 "err reading vin cal for id %x", pvindev->id);
302 goto done;
303 }
304 if (slope != 0 && intercept != 0) {
305 pvindev->slope = slope;
306 pvindev->intercept = intercept;
307 }
308 }
309 }
310 status = BOARDOBJGRP_PMU_CMD_GRP_GET_STATUS_CONSTRUCT(g,
311 &g->clk_pmu.avfs_vinobjs.super.super,
312 clk, CLK, clk_vin_device, CLK_VIN_DEVICE);
313 if (status) {
314 nvgpu_err(g,
315 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
316 status);
317 goto done;
318 }
319
320done:
321 gk20a_dbg_info(" done status %x", status);
322 return status;
323}
324
325u32 clk_vin_pmu_setup(struct gk20a *g)
326{
327 u32 status;
328 struct boardobjgrp *pboardobjgrp = NULL;
329
330 gk20a_dbg_info("");
331
332 pboardobjgrp = &g->clk_pmu.avfs_vinobjs.super.super;
333
334 if (!pboardobjgrp->bconstructed)
335 return -EINVAL;
336
337 status = pboardobjgrp->pmuinithandle(g, pboardobjgrp);
338
339 gk20a_dbg_info("Done");
340 return status;
341}
342
343static u32 devinit_get_vin_device_table(struct gk20a *g,
344 struct avfsvinobjs *pvinobjs)
345{
346 u32 status = 0;
347 u8 *vin_table_ptr = NULL;
348 struct vin_descriptor_header_10 vin_desc_table_header = { 0 };
349 struct vin_descriptor_entry_10 vin_desc_table_entry = { 0 };
350 u8 *vin_tbl_entry_ptr = NULL;
351 u32 index = 0;
352 u32 slope, intercept;
353 struct vin_device vin_dev_data;
354 struct vin_device *pvin_dev;
355
356 gk20a_dbg_info("");
357
358 vin_table_ptr = (u8 *)nvgpu_bios_get_perf_table_ptrs(g,
359 g->bios.clock_token, VIN_TABLE);
360 if (vin_table_ptr == NULL) {
361 status = -1;
362 goto done;
363 }
364
365 memcpy(&vin_desc_table_header, vin_table_ptr,
366 sizeof(struct vin_descriptor_header_10));
367
368 pvinobjs->calibration_rev_vbios =
369 BIOS_GET_FIELD(vin_desc_table_header.flags0,
370 NV_VIN_DESC_FLAGS0_VIN_CAL_REVISION);
371 pvinobjs->vin_is_disable_allowed =
372 BIOS_GET_FIELD(vin_desc_table_header.flags0,
373 NV_VIN_DESC_FLAGS0_DISABLE_CONTROL);
374
375 /* VIN calibration slope: XX.YYY mV/code => XXYYY uV/code*/
376 slope = ((BIOS_GET_FIELD(vin_desc_table_header.vin_cal,
377 NV_VIN_DESC_VIN_CAL_SLOPE_INTEGER) * 1000)) +
378 ((BIOS_GET_FIELD(vin_desc_table_header.vin_cal,
379 NV_VIN_DESC_VIN_CAL_SLOPE_FRACTION)));
380
381 /* VIN calibration intercept: ZZZ.W mV => ZZZW00 uV */
382 intercept = ((BIOS_GET_FIELD(vin_desc_table_header.vin_cal,
383 NV_VIN_DESC_VIN_CAL_INTERCEPT_INTEGER) * 1000)) +
384 ((BIOS_GET_FIELD(vin_desc_table_header.vin_cal,
385 NV_VIN_DESC_VIN_CAL_INTERCEPT_FRACTION) * 100));
386
387 /* Read table entries*/
388 vin_tbl_entry_ptr = vin_table_ptr + vin_desc_table_header.header_sizee;
389 for (index = 0; index < vin_desc_table_header.entry_count; index++) {
390 u32 vin_id;
391
392 memcpy(&vin_desc_table_entry, vin_tbl_entry_ptr,
393 sizeof(struct vin_descriptor_entry_10));
394
395 if (vin_desc_table_entry.vin_device_type == CTRL_CLK_VIN_TYPE_DISABLED)
396 continue;
397
398 vin_id = vin_desc_table_entry.vin_device_id;
399
400 vin_dev_data.super.type =
401 (u8)vin_desc_table_entry.vin_device_type;
402 vin_dev_data.id = (u8)vin_desc_table_entry.vin_device_id;
403 vin_dev_data.volt_domain_vbios =
404 (u8)vin_desc_table_entry.volt_domain_vbios;
405 vin_dev_data.slope = slope;
406 vin_dev_data.intercept = intercept;
407
408 vin_dev_data.flls_shared_mask = 0;
409
410 pvin_dev = construct_vin_device(g, (void *)&vin_dev_data);
411
412 status = boardobjgrp_objinsert(&pvinobjs->super.super,
413 (struct boardobj *)pvin_dev, index);
414
415 vin_tbl_entry_ptr += vin_desc_table_header.entry_size;
416 }
417
418done:
419 gk20a_dbg_info(" done status %x", status);
420 return status;
421}
422
423static struct vin_device *construct_vin_device(struct gk20a *g, void *pargs)
424{
425 struct boardobj *board_obj_ptr = NULL;
426 struct vin_device *pvin_dev;
427 struct vin_device *board_obj_vin_ptr = NULL;
428 u32 status;
429
430 gk20a_dbg_info("");
431 status = boardobj_construct_super(g, &board_obj_ptr,
432 sizeof(struct vin_device), pargs);
433 if (status)
434 return NULL;
435
436 /*got vin board obj allocated now fill it into boardobj grp*/
437 pvin_dev = (struct vin_device *)pargs;
438 board_obj_vin_ptr = (struct vin_device *)board_obj_ptr;
439 /* override super class interface */
440 board_obj_ptr->pmudatainit = vin_device_init_pmudata_super;
441 board_obj_vin_ptr->id = pvin_dev->id;
442 board_obj_vin_ptr->volt_domain_vbios = pvin_dev->volt_domain_vbios;
443 board_obj_vin_ptr->slope = pvin_dev->slope;
444 board_obj_vin_ptr->intercept = pvin_dev->intercept;
445 board_obj_vin_ptr->flls_shared_mask = pvin_dev->flls_shared_mask;
446 board_obj_vin_ptr->volt_domain = CTRL_VOLT_DOMAIN_LOGIC;
447
448 gk20a_dbg_info(" Done");
449
450 return (struct vin_device *)board_obj_ptr;
451}
452
453static u32 vin_device_init_pmudata_super(struct gk20a *g,
454 struct boardobj *board_obj_ptr,
455 struct nv_pmu_boardobj *ppmudata)
456{
457 u32 status = 0;
458 struct vin_device *pvin_dev;
459 struct nv_pmu_clk_clk_vin_device_boardobj_set *perf_pmu_data;
460
461 gk20a_dbg_info("");
462
463 status = boardobj_pmudatainit_super(g, board_obj_ptr, ppmudata);
464 if (status != 0)
465 return status;
466
467 pvin_dev = (struct vin_device *)board_obj_ptr;
468 perf_pmu_data = (struct nv_pmu_clk_clk_vin_device_boardobj_set *)
469 ppmudata;
470
471 perf_pmu_data->id = pvin_dev->id;
472 perf_pmu_data->intercept = pvin_dev->intercept;
473 perf_pmu_data->volt_domain = pvin_dev->volt_domain;
474 perf_pmu_data->slope = pvin_dev->slope;
475 perf_pmu_data->flls_shared_mask = pvin_dev->flls_shared_mask;
476
477 gk20a_dbg_info(" Done");
478
479 return status;
480}
diff --git a/drivers/gpu/nvgpu/clk/clk_vin.h b/drivers/gpu/nvgpu/clk/clk_vin.h
new file mode 100644
index 00000000..3ce26c8a
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk_vin.h
@@ -0,0 +1,65 @@
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#ifndef _CLKVIN_H_
24#define _CLKVIN_H_
25
26#include "boardobj/boardobj.h"
27#include "boardobj/boardobjgrp.h"
28#include "boardobj/boardobjgrp_e32.h"
29
30struct vin_device;
31struct clk_pmupstate;
32
33struct avfsvinobjs {
34 struct boardobjgrp_e32 super;
35 u8 calibration_rev_vbios;
36 u8 calibration_rev_fused;
37 bool vin_is_disable_allowed;
38};
39typedef u32 vin_device_state_load(struct gk20a *g,
40 struct clk_pmupstate *clk, struct vin_device *pdev);
41
42struct vin_device {
43 struct boardobj super;
44 u8 id;
45 u8 volt_domain;
46 u8 volt_domain_vbios;
47 u32 slope;
48 u32 intercept;
49 u32 flls_shared_mask;
50
51 vin_device_state_load *state_load;
52};
53
54/* get vin device object from descriptor table index*/
55#define CLK_GET_VIN_DEVICE(pvinobjs, dev_index) \
56 ((struct vin_device *)BOARDOBJGRP_OBJ_GET_BY_IDX( \
57 ((struct boardobjgrp *)&(pvinobjs->super.super)), (dev_index)))
58
59boardobj_construct construct_vindevice;
60boardobj_pmudatainit vindeviceinit_pmudata_super;
61
62u32 clk_vin_sw_setup(struct gk20a *g);
63u32 clk_vin_pmu_setup(struct gk20a *g);
64
65#endif