aboutsummaryrefslogtreecommitdiffstats
path: root/include/clk
diff options
context:
space:
mode:
authorJoshua Bakita <bakitajoshua@gmail.com>2023-06-28 18:24:25 -0400
committerJoshua Bakita <bakitajoshua@gmail.com>2023-06-28 18:24:25 -0400
commit01e6fac4d61fdd7fff5433942ec93fc2ea1e4df1 (patch)
tree4ef34501728a087be24f4ba0af90f91486bf780b /include/clk
parent306a03d18b305e4e573be3b2931978fa10679eb9 (diff)
Include nvgpu headers
These are needed to build on NVIDIA's Jetson boards for the time being. Only a couple structs are required, so it should be fairly easy to remove this dependency at some point in the future.
Diffstat (limited to 'include/clk')
-rw-r--r--include/clk/clk.c942
-rw-r--r--include/clk/clk.h144
-rw-r--r--include/clk/clk_arb.c1087
-rw-r--r--include/clk/clk_domain.c1666
-rw-r--r--include/clk/clk_domain.h157
-rw-r--r--include/clk/clk_fll.c495
-rw-r--r--include/clk/clk_fll.h81
-rw-r--r--include/clk/clk_freq_controller.c462
-rw-r--r--include/clk/clk_freq_controller.h84
-rw-r--r--include/clk/clk_mclk.h60
-rw-r--r--include/clk/clk_prog.c1152
-rw-r--r--include/clk/clk_prog.h100
-rw-r--r--include/clk/clk_vf_point.c433
-rw-r--r--include/clk/clk_vf_point.h83
-rw-r--r--include/clk/clk_vin.c573
-rw-r--r--include/clk/clk_vin.h79
16 files changed, 7598 insertions, 0 deletions
diff --git a/include/clk/clk.c b/include/clk/clk.c
new file mode 100644
index 0000000..d8e30c4
--- /dev/null
+++ b/include/clk/clk.c
@@ -0,0 +1,942 @@
1/*
2 * Copyright (c) 2016-2018, 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#include <nvgpu/gk20a.h>
26
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 nvgpu_log_info(g, " ");
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}
58
59
60int clk_pmu_freq_effective_avg_load(struct gk20a *g, bool bload)
61{
62 struct pmu_cmd cmd;
63 struct pmu_payload payload;
64 u32 status;
65 u32 seqdesc;
66 struct nv_pmu_clk_rpc rpccall;
67 struct clkrpc_pmucmdhandler_params handler;
68 struct nv_pmu_clk_load *clkload;
69
70 memset(&payload, 0, sizeof(struct pmu_payload));
71 memset(&rpccall, 0, sizeof(struct nv_pmu_clk_rpc));
72 memset(&handler, 0, sizeof(struct clkrpc_pmucmdhandler_params));
73 memset(&cmd, 0, sizeof(struct pmu_cmd));
74
75 rpccall.function = NV_PMU_CLK_RPC_ID_LOAD;
76 clkload = &rpccall.params.clk_load;
77 clkload->feature = NV_NV_PMU_CLK_LOAD_FEATURE_FREQ_EFFECTIVE_AVG;
78 clkload->action_mask = bload ?
79 NV_NV_PMU_CLK_LOAD_ACTION_MASK_FREQ_EFFECTIVE_AVG_CALLBACK_YES :
80 NV_NV_PMU_CLK_LOAD_ACTION_MASK_FREQ_EFFECTIVE_AVG_CALLBACK_NO;
81
82 cmd.hdr.unit_id = PMU_UNIT_CLK;
83 cmd.hdr.size = (u32)sizeof(struct nv_pmu_clk_cmd) +
84 (u32)sizeof(struct pmu_hdr);
85
86 cmd.cmd.clk.cmd_type = NV_PMU_CLK_CMD_ID_RPC;
87
88 payload.in.buf = (u8 *)&rpccall;
89 payload.in.size = (u32)sizeof(struct nv_pmu_clk_rpc);
90 payload.in.fb_size = PMU_CMD_SUBMIT_PAYLOAD_PARAMS_FB_SIZE_UNUSED;
91 payload.in.offset = NV_PMU_CLK_CMD_RPC_ALLOC_OFFSET;
92
93 payload.out.buf = (u8 *)&rpccall;
94 payload.out.size = (u32)sizeof(struct nv_pmu_clk_rpc);
95 payload.out.fb_size = PMU_CMD_SUBMIT_PAYLOAD_PARAMS_FB_SIZE_UNUSED;
96 payload.out.offset = NV_PMU_CLK_MSG_RPC_ALLOC_OFFSET;
97
98 handler.prpccall = &rpccall;
99 handler.success = 0;
100
101 status = nvgpu_pmu_cmd_post(g, &cmd, NULL, &payload,
102 PMU_COMMAND_QUEUE_LPQ,
103 clkrpc_pmucmdhandler, (void *)&handler,
104 &seqdesc, ~0);
105 if (status) {
106 nvgpu_err(g, "unable to post clk RPC cmd %x",
107 cmd.cmd.clk.cmd_type);
108 goto done;
109 }
110
111 pmu_wait_message_cond(&g->pmu,
112 gk20a_get_gr_idle_timeout(g),
113 &handler.success, 1);
114 if (handler.success == 0) {
115 nvgpu_err(g, "rpc call to load Effective avg clk domain freq failed");
116 status = -EINVAL;
117 }
118
119done:
120 return status;
121}
122
123u32 clk_freq_effective_avg(struct gk20a *g, u32 clkDomainMask) {
124
125 struct pmu_cmd cmd;
126 struct pmu_payload payload;
127 u32 status;
128 u32 seqdesc;
129 struct nv_pmu_clk_rpc rpccall;
130 struct clkrpc_pmucmdhandler_params handler;
131 struct nv_pmu_clk_freq_effective_avg *clk_freq_effective_avg;
132
133 memset(&payload, 0, sizeof(struct pmu_payload));
134 memset(&rpccall, 0, sizeof(struct nv_pmu_clk_rpc));
135 memset(&handler, 0, sizeof(struct clkrpc_pmucmdhandler_params));
136 memset(&cmd, 0, sizeof(struct pmu_cmd));
137
138 rpccall.function = NV_PMU_CLK_RPC_ID_CLK_FREQ_EFF_AVG;
139 clk_freq_effective_avg = &rpccall.params.clk_freq_effective_avg;
140 clk_freq_effective_avg->clkDomainMask = clkDomainMask;
141
142 cmd.hdr.unit_id = PMU_UNIT_CLK;
143 cmd.hdr.size = (u32)sizeof(struct nv_pmu_clk_cmd) +
144 (u32)sizeof(struct pmu_hdr);
145
146 cmd.cmd.clk.cmd_type = NV_PMU_CLK_CMD_ID_RPC;
147
148 payload.in.buf = (u8 *)&rpccall;
149 payload.in.size = (u32)sizeof(struct nv_pmu_clk_rpc);
150 payload.in.fb_size = PMU_CMD_SUBMIT_PAYLOAD_PARAMS_FB_SIZE_UNUSED;
151 payload.in.offset = NV_PMU_CLK_CMD_RPC_ALLOC_OFFSET;
152
153 payload.out.buf = (u8 *)&rpccall;
154 payload.out.size = (u32)sizeof(struct nv_pmu_clk_rpc);
155 payload.out.fb_size = PMU_CMD_SUBMIT_PAYLOAD_PARAMS_FB_SIZE_UNUSED;
156 payload.out.offset = NV_PMU_CLK_MSG_RPC_ALLOC_OFFSET;
157
158 handler.prpccall = &rpccall;
159 handler.success = 0;
160
161 status = nvgpu_pmu_cmd_post(g, &cmd, NULL, &payload,
162 PMU_COMMAND_QUEUE_LPQ,
163 clkrpc_pmucmdhandler, (void *)&handler,
164 &seqdesc, ~0);
165 if (status) {
166 nvgpu_err(g, "unable to post clk RPC cmd %x",
167 cmd.cmd.clk.cmd_type);
168 goto done;
169 }
170
171 pmu_wait_message_cond(&g->pmu,
172 gk20a_get_gr_idle_timeout(g),
173 &handler.success, 1);
174 if (handler.success == 0) {
175 nvgpu_err(g, "rpc call to get clk frequency average failed");
176 status = -EINVAL;
177 goto done;
178 }
179
180 return rpccall.params.clk_freq_effective_avg.freqkHz[clkDomainMask];
181
182done:
183 return status;
184}
185
186int clk_pmu_freq_controller_load(struct gk20a *g, bool bload, u8 bit_idx)
187{
188 struct pmu_cmd cmd;
189 struct pmu_payload payload;
190 u32 status;
191 u32 seqdesc;
192 struct nv_pmu_clk_rpc rpccall;
193 struct clkrpc_pmucmdhandler_params handler;
194 struct nv_pmu_clk_load *clkload;
195 struct clk_freq_controllers *pclk_freq_controllers;
196 struct ctrl_boardobjgrp_mask_e32 *load_mask;
197 struct boardobjgrpmask_e32 isolate_cfc_mask;
198
199 memset(&payload, 0, sizeof(struct pmu_payload));
200 memset(&rpccall, 0, sizeof(struct nv_pmu_clk_rpc));
201 memset(&handler, 0, sizeof(struct clkrpc_pmucmdhandler_params));
202
203 pclk_freq_controllers = &g->clk_pmu.clk_freq_controllers;
204 rpccall.function = NV_PMU_CLK_RPC_ID_LOAD;
205 clkload = &rpccall.params.clk_load;
206 clkload->feature = NV_NV_PMU_CLK_LOAD_FEATURE_FREQ_CONTROLLER;
207 clkload->action_mask = bload ?
208 NV_NV_PMU_CLK_LOAD_ACTION_MASK_FREQ_CONTROLLER_CALLBACK_YES :
209 NV_NV_PMU_CLK_LOAD_ACTION_MASK_FREQ_CONTROLLER_CALLBACK_NO;
210
211 load_mask = &rpccall.params.clk_load.payload.freq_controllers.load_mask;
212
213 status = boardobjgrpmask_e32_init(&isolate_cfc_mask, NULL);
214
215 if (bit_idx == CTRL_CLK_CLK_FREQ_CONTROLLER_ID_ALL) {
216 status = boardobjgrpmask_export(
217 &pclk_freq_controllers->
218 freq_ctrl_load_mask.super,
219 pclk_freq_controllers->
220 freq_ctrl_load_mask.super.bitcount,
221 &load_mask->super);
222
223
224 } else {
225 status = boardobjgrpmask_bitset(&isolate_cfc_mask.super,
226 bit_idx);
227 status = boardobjgrpmask_export(&isolate_cfc_mask.super,
228 isolate_cfc_mask.super.bitcount,
229 &load_mask->super);
230 if (bload) {
231 status = boardobjgrpmask_bitset(
232 &pclk_freq_controllers->
233 freq_ctrl_load_mask.super,
234 bit_idx);
235 } else {
236 status = boardobjgrpmask_bitclr(
237 &pclk_freq_controllers->
238 freq_ctrl_load_mask.super,
239 bit_idx);
240 }
241 }
242
243 if (status) {
244 nvgpu_err(g, "Error in generating mask used to select CFC");
245 goto done;
246 }
247
248 cmd.hdr.unit_id = PMU_UNIT_CLK;
249 cmd.hdr.size = (u32)sizeof(struct nv_pmu_clk_cmd) +
250 (u32)sizeof(struct pmu_hdr);
251
252 cmd.cmd.clk.cmd_type = NV_PMU_CLK_CMD_ID_RPC;
253
254 payload.in.buf = (u8 *)&rpccall;
255 payload.in.size = (u32)sizeof(struct nv_pmu_clk_rpc);
256 payload.in.fb_size = PMU_CMD_SUBMIT_PAYLOAD_PARAMS_FB_SIZE_UNUSED;
257 payload.in.offset = NV_PMU_CLK_CMD_RPC_ALLOC_OFFSET;
258
259 payload.out.buf = (u8 *)&rpccall;
260 payload.out.size = (u32)sizeof(struct nv_pmu_clk_rpc);
261 payload.out.fb_size = PMU_CMD_SUBMIT_PAYLOAD_PARAMS_FB_SIZE_UNUSED;
262 payload.out.offset = NV_PMU_CLK_MSG_RPC_ALLOC_OFFSET;
263
264 handler.prpccall = &rpccall;
265 handler.success = 0;
266 status = nvgpu_pmu_cmd_post(g, &cmd, NULL, &payload,
267 PMU_COMMAND_QUEUE_LPQ,
268 clkrpc_pmucmdhandler, (void *)&handler,
269 &seqdesc, ~0);
270
271 if (status) {
272 nvgpu_err(g, "unable to post clk RPC cmd %x",
273 cmd.cmd.clk.cmd_type);
274 goto done;
275 }
276
277 pmu_wait_message_cond(&g->pmu,
278 gk20a_get_gr_idle_timeout(g),
279 &handler.success, 1);
280
281 if (handler.success == 0) {
282 nvgpu_err(g, "rpc call to load freq cntlr cal failed");
283 status = -EINVAL;
284 }
285
286done:
287 return status;
288}
289
290u32 clk_pmu_vin_load(struct gk20a *g)
291{
292 struct pmu_cmd cmd;
293 struct pmu_payload payload;
294 u32 status;
295 u32 seqdesc;
296 struct nv_pmu_clk_rpc rpccall;
297 struct clkrpc_pmucmdhandler_params handler;
298 struct nv_pmu_clk_load *clkload;
299
300 memset(&payload, 0, sizeof(struct pmu_payload));
301 memset(&rpccall, 0, sizeof(struct nv_pmu_clk_rpc));
302 memset(&handler, 0, sizeof(struct clkrpc_pmucmdhandler_params));
303
304 rpccall.function = NV_PMU_CLK_RPC_ID_LOAD;
305 clkload = &rpccall.params.clk_load;
306 clkload->feature = NV_NV_PMU_CLK_LOAD_FEATURE_VIN;
307 clkload->action_mask = NV_NV_PMU_CLK_LOAD_ACTION_MASK_VIN_HW_CAL_PROGRAM_YES << 4;
308
309 cmd.hdr.unit_id = PMU_UNIT_CLK;
310 cmd.hdr.size = (u32)sizeof(struct nv_pmu_clk_cmd) +
311 (u32)sizeof(struct pmu_hdr);
312
313 cmd.cmd.clk.cmd_type = NV_PMU_CLK_CMD_ID_RPC;
314 cmd.cmd.clk.generic.b_perf_daemon_cmd =false;
315
316 payload.in.buf = (u8 *)&rpccall;
317 payload.in.size = (u32)sizeof(struct nv_pmu_clk_rpc);
318 payload.in.fb_size = PMU_CMD_SUBMIT_PAYLOAD_PARAMS_FB_SIZE_UNUSED;
319 payload.in.offset = NV_PMU_CLK_CMD_RPC_ALLOC_OFFSET;
320
321 payload.out.buf = (u8 *)&rpccall;
322 payload.out.size = (u32)sizeof(struct nv_pmu_clk_rpc);
323 payload.out.fb_size = PMU_CMD_SUBMIT_PAYLOAD_PARAMS_FB_SIZE_UNUSED;
324 payload.out.offset = NV_PMU_CLK_MSG_RPC_ALLOC_OFFSET;
325
326 handler.prpccall = &rpccall;
327 handler.success = 0;
328 status = nvgpu_pmu_cmd_post(g, &cmd, NULL, &payload,
329 PMU_COMMAND_QUEUE_LPQ,
330 clkrpc_pmucmdhandler, (void *)&handler,
331 &seqdesc, ~0);
332
333 if (status) {
334 nvgpu_err(g, "unable to post clk RPC cmd %x",
335 cmd.cmd.clk.cmd_type);
336 goto done;
337 }
338
339 pmu_wait_message_cond(&g->pmu,
340 gk20a_get_gr_idle_timeout(g),
341 &handler.success, 1);
342
343 if (handler.success == 0) {
344 nvgpu_err(g, "rpc call to load vin cal failed");
345 status = -EINVAL;
346 }
347
348done:
349 return status;
350}
351
352u32 nvgpu_clk_vf_change_inject_data_fill_gp10x(struct gk20a *g,
353 struct nv_pmu_clk_rpc *rpccall,
354 struct set_fll_clk *setfllclk)
355{
356 struct nv_pmu_clk_vf_change_inject *vfchange;
357
358 vfchange = &rpccall->params.clk_vf_change_inject;
359 vfchange->flags = 0;
360 vfchange->clk_list.num_domains = 3;
361 vfchange->clk_list.clk_domains[0].clk_domain = CTRL_CLK_DOMAIN_GPC2CLK;
362 vfchange->clk_list.clk_domains[0].clk_freq_khz =
363 setfllclk->gpc2clkmhz * 1000;
364 vfchange->clk_list.clk_domains[0].clk_flags = 0;
365 vfchange->clk_list.clk_domains[0].current_regime_id =
366 setfllclk->current_regime_id_gpc;
367 vfchange->clk_list.clk_domains[0].target_regime_id =
368 setfllclk->target_regime_id_gpc;
369 vfchange->clk_list.clk_domains[1].clk_domain = CTRL_CLK_DOMAIN_XBAR2CLK;
370 vfchange->clk_list.clk_domains[1].clk_freq_khz =
371 setfllclk->xbar2clkmhz * 1000;
372 vfchange->clk_list.clk_domains[1].clk_flags = 0;
373 vfchange->clk_list.clk_domains[1].current_regime_id =
374 setfllclk->current_regime_id_xbar;
375 vfchange->clk_list.clk_domains[1].target_regime_id =
376 setfllclk->target_regime_id_xbar;
377 vfchange->clk_list.clk_domains[2].clk_domain = CTRL_CLK_DOMAIN_SYS2CLK;
378 vfchange->clk_list.clk_domains[2].clk_freq_khz =
379 setfllclk->sys2clkmhz * 1000;
380 vfchange->clk_list.clk_domains[2].clk_flags = 0;
381 vfchange->clk_list.clk_domains[2].current_regime_id =
382 setfllclk->current_regime_id_sys;
383 vfchange->clk_list.clk_domains[2].target_regime_id =
384 setfllclk->target_regime_id_sys;
385 vfchange->volt_list.num_rails = 1;
386 vfchange->volt_list.rails[0].volt_domain = CTRL_VOLT_DOMAIN_LOGIC;
387 vfchange->volt_list.rails[0].voltage_uv = setfllclk->voltuv;
388 vfchange->volt_list.rails[0].voltage_min_noise_unaware_uv =
389 setfllclk->voltuv;
390
391 return 0;
392}
393
394u32 nvgpu_clk_vf_change_inject_data_fill_gv10x(struct gk20a *g,
395 struct nv_pmu_clk_rpc *rpccall,
396 struct set_fll_clk *setfllclk)
397{
398 struct nv_pmu_clk_vf_change_inject_v1 *vfchange;
399
400 vfchange = &rpccall->params.clk_vf_change_inject_v1;
401 vfchange->flags = 0;
402 vfchange->clk_list.num_domains = 4;
403 vfchange->clk_list.clk_domains[0].clk_domain = CTRL_CLK_DOMAIN_GPCCLK;
404 vfchange->clk_list.clk_domains[0].clk_freq_khz =
405 setfllclk->gpc2clkmhz * 1000;
406
407 vfchange->clk_list.clk_domains[1].clk_domain = CTRL_CLK_DOMAIN_XBARCLK;
408 vfchange->clk_list.clk_domains[1].clk_freq_khz =
409 setfllclk->xbar2clkmhz * 1000;
410
411 vfchange->clk_list.clk_domains[2].clk_domain = CTRL_CLK_DOMAIN_SYSCLK;
412 vfchange->clk_list.clk_domains[2].clk_freq_khz =
413 setfllclk->sys2clkmhz * 1000;
414
415 vfchange->clk_list.clk_domains[3].clk_domain = CTRL_CLK_DOMAIN_NVDCLK;
416 vfchange->clk_list.clk_domains[3].clk_freq_khz = 855 * 1000;
417
418 vfchange->volt_list.num_rails = 1;
419 vfchange->volt_list.rails[0].rail_idx = 0;
420 vfchange->volt_list.rails[0].voltage_uv = setfllclk->voltuv;
421 vfchange->volt_list.rails[0].voltage_min_noise_unaware_uv =
422 setfllclk->voltuv;
423
424 return 0;
425}
426
427static u32 clk_pmu_vf_inject(struct gk20a *g, struct set_fll_clk *setfllclk)
428{
429 struct pmu_cmd cmd;
430 struct pmu_payload payload;
431 u32 status;
432 u32 seqdesc;
433 struct nv_pmu_clk_rpc rpccall;
434 struct clkrpc_pmucmdhandler_params handler;
435
436 memset(&payload, 0, sizeof(struct pmu_payload));
437 memset(&rpccall, 0, sizeof(struct nv_pmu_clk_rpc));
438 memset(&handler, 0, sizeof(struct clkrpc_pmucmdhandler_params));
439 memset(&cmd, 0, sizeof(struct pmu_cmd));
440
441 if ((setfllclk->gpc2clkmhz == 0) || (setfllclk->xbar2clkmhz == 0) ||
442 (setfllclk->sys2clkmhz == 0) || (setfllclk->voltuv == 0)) {
443 return -EINVAL;
444 }
445
446 if ((setfllclk->target_regime_id_gpc > CTRL_CLK_FLL_REGIME_ID_FR) ||
447 (setfllclk->target_regime_id_sys > CTRL_CLK_FLL_REGIME_ID_FR) ||
448 (setfllclk->target_regime_id_xbar > CTRL_CLK_FLL_REGIME_ID_FR)) {
449 return -EINVAL;
450 }
451
452 rpccall.function = NV_PMU_CLK_RPC_ID_CLK_VF_CHANGE_INJECT;
453
454 g->ops.pmu_ver.clk.clk_vf_change_inject_data_fill(g,
455 &rpccall, setfllclk);
456
457 cmd.hdr.unit_id = PMU_UNIT_CLK;
458 cmd.hdr.size = (u32)sizeof(struct nv_pmu_clk_cmd) +
459 (u32)sizeof(struct pmu_hdr);
460
461 cmd.cmd.clk.cmd_type = NV_PMU_CLK_CMD_ID_RPC;
462
463 payload.in.buf = (u8 *)&rpccall;
464 payload.in.size = (u32)sizeof(struct nv_pmu_clk_rpc);
465 payload.in.fb_size = PMU_CMD_SUBMIT_PAYLOAD_PARAMS_FB_SIZE_UNUSED;
466 payload.in.offset = NV_PMU_CLK_CMD_RPC_ALLOC_OFFSET;
467
468 payload.out.buf = (u8 *)&rpccall;
469 payload.out.size = (u32)sizeof(struct nv_pmu_clk_rpc);
470 payload.out.fb_size = PMU_CMD_SUBMIT_PAYLOAD_PARAMS_FB_SIZE_UNUSED;
471 payload.out.offset = NV_PMU_CLK_MSG_RPC_ALLOC_OFFSET;
472
473 handler.prpccall = &rpccall;
474 handler.success = 0;
475
476 status = nvgpu_pmu_cmd_post(g, &cmd, NULL, &payload,
477 PMU_COMMAND_QUEUE_LPQ,
478 clkrpc_pmucmdhandler, (void *)&handler,
479 &seqdesc, ~0);
480
481 if (status) {
482 nvgpu_err(g, "unable to post clk RPC cmd %x",
483 cmd.cmd.clk.cmd_type);
484 goto done;
485 }
486
487 pmu_wait_message_cond(&g->pmu,
488 gk20a_get_gr_idle_timeout(g),
489 &handler.success, 1);
490
491 if (handler.success == 0) {
492 nvgpu_err(g, "rpc call to inject clock failed");
493 status = -EINVAL;
494 }
495done:
496 return status;
497}
498
499static u32 find_regime_id(struct gk20a *g, u32 domain, u16 clkmhz)
500{
501 struct fll_device *pflldev;
502 u8 j;
503 struct clk_pmupstate *pclk = &g->clk_pmu;
504
505 BOARDOBJGRP_FOR_EACH(&(pclk->avfs_fllobjs.super.super),
506 struct fll_device *, pflldev, j) {
507 if (pflldev->clk_domain == domain) {
508 if (pflldev->regime_desc.fixed_freq_regime_limit_mhz >=
509 clkmhz) {
510 return CTRL_CLK_FLL_REGIME_ID_FFR;
511 } else {
512 return CTRL_CLK_FLL_REGIME_ID_FR;
513 }
514 }
515 }
516 return CTRL_CLK_FLL_REGIME_ID_INVALID;
517}
518
519static int set_regime_id(struct gk20a *g, u32 domain, u32 regimeid)
520{
521 struct fll_device *pflldev;
522 u8 j;
523 struct clk_pmupstate *pclk = &g->clk_pmu;
524
525 BOARDOBJGRP_FOR_EACH(&(pclk->avfs_fllobjs.super.super),
526 struct fll_device *, pflldev, j) {
527 if (pflldev->clk_domain == domain) {
528 pflldev->regime_desc.regime_id = regimeid;
529 return 0;
530 }
531 }
532 return -EINVAL;
533}
534
535static int get_regime_id(struct gk20a *g, u32 domain, u32 *regimeid)
536{
537 struct fll_device *pflldev;
538 u8 j;
539 struct clk_pmupstate *pclk = &g->clk_pmu;
540
541 BOARDOBJGRP_FOR_EACH(&(pclk->avfs_fllobjs.super.super),
542 struct fll_device *, pflldev, j) {
543 if (pflldev->clk_domain == domain) {
544 *regimeid = pflldev->regime_desc.regime_id;
545 return 0;
546 }
547 }
548 return -EINVAL;
549}
550
551int clk_set_fll_clks(struct gk20a *g, struct set_fll_clk *setfllclk)
552{
553 int status = -EINVAL;
554
555 /*set regime ids */
556 status = get_regime_id(g, CTRL_CLK_DOMAIN_GPC2CLK,
557 &setfllclk->current_regime_id_gpc);
558 if (status) {
559 goto done;
560 }
561
562 setfllclk->target_regime_id_gpc = find_regime_id(g,
563 CTRL_CLK_DOMAIN_GPC2CLK, setfllclk->gpc2clkmhz);
564
565 status = get_regime_id(g, CTRL_CLK_DOMAIN_SYS2CLK,
566 &setfllclk->current_regime_id_sys);
567 if (status) {
568 goto done;
569 }
570
571 setfllclk->target_regime_id_sys = find_regime_id(g,
572 CTRL_CLK_DOMAIN_SYS2CLK, setfllclk->sys2clkmhz);
573
574 status = get_regime_id(g, CTRL_CLK_DOMAIN_XBAR2CLK,
575 &setfllclk->current_regime_id_xbar);
576 if (status) {
577 goto done;
578 }
579
580 setfllclk->target_regime_id_xbar = find_regime_id(g,
581 CTRL_CLK_DOMAIN_XBAR2CLK, setfllclk->xbar2clkmhz);
582
583 status = clk_pmu_vf_inject(g, setfllclk);
584
585 if (status) {
586 nvgpu_err(g, "vf inject to change clk failed");
587 }
588
589 /* save regime ids */
590 status = set_regime_id(g, CTRL_CLK_DOMAIN_XBAR2CLK,
591 setfllclk->target_regime_id_xbar);
592 if (status) {
593 goto done;
594 }
595
596 status = set_regime_id(g, CTRL_CLK_DOMAIN_GPC2CLK,
597 setfllclk->target_regime_id_gpc);
598 if (status) {
599 goto done;
600 }
601
602 status = set_regime_id(g, CTRL_CLK_DOMAIN_SYS2CLK,
603 setfllclk->target_regime_id_sys);
604 if (status) {
605 goto done;
606 }
607done:
608 return status;
609}
610
611int clk_get_fll_clks(struct gk20a *g, struct set_fll_clk *setfllclk)
612{
613 int status = -EINVAL;
614 struct clk_domain *pdomain;
615 u8 i;
616 struct clk_pmupstate *pclk = &g->clk_pmu;
617 u16 clkmhz = 0;
618 struct clk_domain_3x_master *p3xmaster;
619 struct clk_domain_3x_slave *p3xslave;
620 unsigned long slaveidxmask;
621
622 if (setfllclk->gpc2clkmhz == 0) {
623 return -EINVAL;
624 }
625
626 BOARDOBJGRP_FOR_EACH(&(pclk->clk_domainobjs.super.super),
627 struct clk_domain *, pdomain, i) {
628
629 if (pdomain->api_domain == CTRL_CLK_DOMAIN_GPC2CLK) {
630
631 if (!pdomain->super.implements(g, &pdomain->super,
632 CTRL_CLK_CLK_DOMAIN_TYPE_3X_MASTER)) {
633 status = -EINVAL;
634 goto done;
635 }
636 p3xmaster = (struct clk_domain_3x_master *)pdomain;
637 slaveidxmask = p3xmaster->slave_idxs_mask;
638 for_each_set_bit(i, &slaveidxmask, 32) {
639 p3xslave = (struct clk_domain_3x_slave *)
640 CLK_CLK_DOMAIN_GET(pclk, i);
641 if ((p3xslave->super.super.super.api_domain !=
642 CTRL_CLK_DOMAIN_XBAR2CLK) &&
643 (p3xslave->super.super.super.api_domain !=
644 CTRL_CLK_DOMAIN_SYS2CLK)) {
645 continue;
646 }
647 clkmhz = 0;
648 status = p3xslave->clkdomainclkgetslaveclk(g,
649 pclk,
650 (struct clk_domain *)p3xslave,
651 &clkmhz,
652 setfllclk->gpc2clkmhz);
653 if (status) {
654 status = -EINVAL;
655 goto done;
656 }
657 if (p3xslave->super.super.super.api_domain ==
658 CTRL_CLK_DOMAIN_XBAR2CLK) {
659 setfllclk->xbar2clkmhz = clkmhz;
660 }
661 if (p3xslave->super.super.super.api_domain ==
662 CTRL_CLK_DOMAIN_SYS2CLK) {
663 setfllclk->sys2clkmhz = clkmhz;
664 }
665 }
666 }
667 }
668done:
669 return status;
670}
671
672u32 clk_domain_print_vf_table(struct gk20a *g, u32 clkapidomain)
673{
674 u32 status = -EINVAL;
675 struct clk_domain *pdomain;
676 u8 i;
677 struct clk_pmupstate *pclk = &g->clk_pmu;
678 u16 clkmhz = 0;
679 u32 volt = 0;
680
681 BOARDOBJGRP_FOR_EACH(&(pclk->clk_domainobjs.super.super),
682 struct clk_domain *, pdomain, i) {
683 if (pdomain->api_domain == clkapidomain) {
684 status = pdomain->clkdomainclkvfsearch(g, pclk,
685 pdomain, &clkmhz, &volt,
686 CLK_PROG_VFE_ENTRY_LOGIC);
687 status = pdomain->clkdomainclkvfsearch(g, pclk,
688 pdomain, &clkmhz, &volt,
689 CLK_PROG_VFE_ENTRY_SRAM);
690 }
691 }
692 return status;
693}
694
695static int clk_program_fllclks(struct gk20a *g, struct change_fll_clk *fllclk)
696{
697 int status = -EINVAL;
698 struct clk_domain *pdomain;
699 u8 i;
700 struct clk_pmupstate *pclk = &g->clk_pmu;
701 u16 clkmhz = 0;
702 struct clk_domain_3x_master *p3xmaster;
703 struct clk_domain_3x_slave *p3xslave;
704 unsigned long slaveidxmask;
705 struct set_fll_clk setfllclk;
706
707 if (fllclk->api_clk_domain != CTRL_CLK_DOMAIN_GPCCLK) {
708 return -EINVAL;
709 }
710 if (fllclk->voltuv == 0) {
711 return -EINVAL;
712 }
713 if (fllclk->clkmhz == 0) {
714 return -EINVAL;
715 }
716
717 setfllclk.voltuv = fllclk->voltuv;
718 setfllclk.gpc2clkmhz = fllclk->clkmhz;
719
720 BOARDOBJGRP_FOR_EACH(&(pclk->clk_domainobjs.super.super),
721 struct clk_domain *, pdomain, i) {
722
723 if (pdomain->api_domain == fllclk->api_clk_domain) {
724
725 if (!pdomain->super.implements(g, &pdomain->super,
726 CTRL_CLK_CLK_DOMAIN_TYPE_3X_MASTER)) {
727 status = -EINVAL;
728 goto done;
729 }
730 p3xmaster = (struct clk_domain_3x_master *)pdomain;
731 slaveidxmask = p3xmaster->slave_idxs_mask;
732 for_each_set_bit(i, &slaveidxmask, 32) {
733 p3xslave = (struct clk_domain_3x_slave *)
734 CLK_CLK_DOMAIN_GET(pclk, i);
735 if ((p3xslave->super.super.super.api_domain !=
736 CTRL_CLK_DOMAIN_XBARCLK) &&
737 (p3xslave->super.super.super.api_domain !=
738 CTRL_CLK_DOMAIN_SYSCLK)) {
739 continue;
740 }
741 clkmhz = 0;
742 status = p3xslave->clkdomainclkgetslaveclk(g,
743 pclk,
744 (struct clk_domain *)p3xslave,
745 &clkmhz,
746 fllclk->clkmhz);
747 if (status) {
748 status = -EINVAL;
749 goto done;
750 }
751 if (p3xslave->super.super.super.api_domain ==
752 CTRL_CLK_DOMAIN_XBARCLK) {
753 setfllclk.xbar2clkmhz = clkmhz;
754 }
755 if (p3xslave->super.super.super.api_domain ==
756 CTRL_CLK_DOMAIN_SYSCLK) {
757 setfllclk.sys2clkmhz = clkmhz;
758 }
759 }
760 }
761 }
762 /*set regime ids */
763 status = get_regime_id(g, CTRL_CLK_DOMAIN_GPCCLK,
764 &setfllclk.current_regime_id_gpc);
765 if (status) {
766 goto done;
767 }
768
769 setfllclk.target_regime_id_gpc = find_regime_id(g,
770 CTRL_CLK_DOMAIN_GPCCLK, setfllclk.gpc2clkmhz);
771
772 status = get_regime_id(g, CTRL_CLK_DOMAIN_SYSCLK,
773 &setfllclk.current_regime_id_sys);
774 if (status) {
775 goto done;
776 }
777
778 setfllclk.target_regime_id_sys = find_regime_id(g,
779 CTRL_CLK_DOMAIN_SYSCLK, setfllclk.sys2clkmhz);
780
781 status = get_regime_id(g, CTRL_CLK_DOMAIN_XBARCLK,
782 &setfllclk.current_regime_id_xbar);
783 if (status) {
784 goto done;
785 }
786
787 setfllclk.target_regime_id_xbar = find_regime_id(g,
788 CTRL_CLK_DOMAIN_XBARCLK, setfllclk.xbar2clkmhz);
789
790 status = clk_pmu_vf_inject(g, &setfllclk);
791
792 if (status) {
793 nvgpu_err(g,
794 "vf inject to change clk failed");
795 }
796
797 /* save regime ids */
798 status = set_regime_id(g, CTRL_CLK_DOMAIN_XBARCLK,
799 setfllclk.target_regime_id_xbar);
800 if (status) {
801 goto done;
802 }
803
804 status = set_regime_id(g, CTRL_CLK_DOMAIN_GPCCLK,
805 setfllclk.target_regime_id_gpc);
806 if (status) {
807 goto done;
808 }
809
810 status = set_regime_id(g, CTRL_CLK_DOMAIN_SYSCLK,
811 setfllclk.target_regime_id_sys);
812 if (status) {
813 goto done;
814 }
815done:
816 return status;
817}
818
819u32 nvgpu_clk_set_boot_fll_clk_gv10x(struct gk20a *g)
820{
821 int status;
822 struct change_fll_clk bootfllclk;
823 u16 gpcclk_clkmhz = BOOT_GPCCLK_MHZ;
824 u32 gpcclk_voltuv = 0;
825 u32 voltuv = 0;
826
827 status = clk_vf_point_cache(g);
828 if (status) {
829 nvgpu_err(g,"caching failed");
830 return status;
831 }
832
833 status = clk_domain_get_f_or_v(g, CTRL_CLK_DOMAIN_GPCCLK,
834 &gpcclk_clkmhz, &gpcclk_voltuv, CTRL_VOLT_DOMAIN_LOGIC);
835 if (status) {
836 return status;
837 }
838
839 voltuv = gpcclk_voltuv;
840
841 status = volt_set_voltage(g, voltuv, 0);
842 if (status) {
843 nvgpu_err(g,
844 "attempt to set boot voltage failed %d",
845 voltuv);
846 }
847
848 bootfllclk.api_clk_domain = CTRL_CLK_DOMAIN_GPCCLK;
849 bootfllclk.clkmhz = gpcclk_clkmhz;
850 bootfllclk.voltuv = voltuv;
851 status = clk_program_fllclks(g, &bootfllclk);
852 if (status) {
853 nvgpu_err(g, "attempt to set boot gpcclk failed");
854 }
855
856 status = clk_pmu_freq_effective_avg_load(g, true);
857
858 /*
859 * Read clocks after some delay with below method
860 * & extract clock data from buffer
861 * clk_freq_effective_avg(g, CTRL_CLK_DOMAIN_GPCCLK |
862 * CTRL_CLK_DOMAIN_XBARCLK |
863 * CTRL_CLK_DOMAIN_SYSCLK |
864 * CTRL_CLK_DOMAIN_NVDCLK)
865 * */
866
867 return status;
868}
869
870int nvgpu_clk_set_fll_clk_gv10x(struct gk20a *g)
871{
872 int status;
873 struct change_fll_clk bootfllclk;
874 u16 gpcclk_clkmhz = BOOT_GPCCLK_MHZ;
875 u32 gpcclk_voltuv = 0U;
876 u32 voltuv = 0U;
877
878 status = clk_vf_point_cache(g);
879 if (status != 0) {
880 nvgpu_err(g, "caching failed");
881 return status;
882 }
883
884 status = clk_domain_get_f_or_v(g, CTRL_CLK_DOMAIN_GPCCLK,
885 &gpcclk_clkmhz, &gpcclk_voltuv, CTRL_VOLT_DOMAIN_LOGIC);
886 if (status != 0) {
887 return status;
888 }
889
890 voltuv = gpcclk_voltuv;
891
892 status = volt_set_voltage(g, voltuv, 0U);
893 if (status != 0) {
894 nvgpu_err(g, "attempt to set max voltage failed %d", voltuv);
895 }
896
897 bootfllclk.api_clk_domain = CTRL_CLK_DOMAIN_GPCCLK;
898 bootfllclk.clkmhz = gpcclk_clkmhz;
899 bootfllclk.voltuv = voltuv;
900 status = clk_program_fllclks(g, &bootfllclk);
901 if (status != 0) {
902 nvgpu_err(g, "attempt to set max gpcclk failed");
903 }
904 return status;
905}
906
907u32 clk_domain_get_f_or_v(
908 struct gk20a *g,
909 u32 clkapidomain,
910 u16 *pclkmhz,
911 u32 *pvoltuv,
912 u8 railidx
913)
914{
915 u32 status = -EINVAL;
916 struct clk_domain *pdomain;
917 u8 i;
918 struct clk_pmupstate *pclk = &g->clk_pmu;
919 u8 rail;
920
921 if ((pclkmhz == NULL) || (pvoltuv == NULL)) {
922 return -EINVAL;
923 }
924
925 if (railidx == CTRL_VOLT_DOMAIN_LOGIC) {
926 rail = CLK_PROG_VFE_ENTRY_LOGIC;
927 } else if (railidx == CTRL_VOLT_DOMAIN_SRAM) {
928 rail = CLK_PROG_VFE_ENTRY_SRAM;
929 } else {
930 return -EINVAL;
931 }
932
933 BOARDOBJGRP_FOR_EACH(&(pclk->clk_domainobjs.super.super),
934 struct clk_domain *, pdomain, i) {
935 if (pdomain->api_domain == clkapidomain) {
936 status = pdomain->clkdomainclkvfsearch(g, pclk,
937 pdomain, pclkmhz, pvoltuv, rail);
938 return status;
939 }
940 }
941 return status;
942}
diff --git a/include/clk/clk.h b/include/clk/clk.h
new file mode 100644
index 0000000..3f4bdf7
--- /dev/null
+++ b/include/clk/clk.h
@@ -0,0 +1,144 @@
1/*
2 * general clock structures & definitions
3 *
4 * Copyright (c) 2016-2018, 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 NVGPU_CLK_H
25#define NVGPU_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#define BOOT_GPCCLK_MHZ 952
39
40struct gk20a;
41
42int clk_set_boot_fll_clk(struct gk20a *g);
43
44/* clock related defines for GPUs supporting clock control from pmu*/
45struct clk_pmupstate {
46 struct avfsvinobjs avfs_vinobjs;
47 struct avfsfllobjs avfs_fllobjs;
48 struct clk_domains clk_domainobjs;
49 struct clk_progs clk_progobjs;
50 struct clk_vf_points clk_vf_pointobjs;
51 struct clk_mclk_state clk_mclk;
52 struct clk_freq_controllers clk_freq_controllers;
53};
54
55struct clockentry {
56 u8 vbios_clk_domain;
57 u8 clk_which;
58 u8 perf_index;
59 u32 api_clk_domain;
60};
61
62struct change_fll_clk {
63 u32 api_clk_domain;
64 u16 clkmhz;
65 u32 voltuv;
66};
67
68struct set_fll_clk {
69 u32 voltuv;
70 u16 gpc2clkmhz;
71 u32 current_regime_id_gpc;
72 u32 target_regime_id_gpc;
73 u16 sys2clkmhz;
74 u32 current_regime_id_sys;
75 u32 target_regime_id_sys;
76 u16 xbar2clkmhz;
77 u32 current_regime_id_xbar;
78 u32 target_regime_id_xbar;
79};
80
81#define NV_PERF_HEADER_4X_CLOCKS_DOMAINS_MAX_NUMCLKS 9
82
83struct vbios_clock_domain {
84 u8 clock_type;
85 u8 num_domains;
86 struct clockentry clock_entry[NV_PERF_HEADER_4X_CLOCKS_DOMAINS_MAX_NUMCLKS];
87};
88
89struct vbios_clocks_table_1x_hal_clock_entry {
90 enum nv_pmu_clk_clkwhich domain;
91 bool b_noise_aware_capable;
92 u8 clk_vf_curve_count;
93};
94
95#define NV_PERF_HEADER_4X_CLOCKS_DOMAINS_4_GPC2CLK 0
96#define NV_PERF_HEADER_4X_CLOCKS_DOMAINS_4_XBAR2CLK 1
97#define NV_PERF_HEADER_4X_CLOCKS_DOMAINS_4_DRAMCLK 2
98#define NV_PERF_HEADER_4X_CLOCKS_DOMAINS_4_SYS2CLK 3
99#define NV_PERF_HEADER_4X_CLOCKS_DOMAINS_4_HUB2CLK 4
100#define NV_PERF_HEADER_4X_CLOCKS_DOMAINS_4_MSDCLK 5
101#define NV_PERF_HEADER_4X_CLOCKS_DOMAINS_4_PWRCLK 6
102#define NV_PERF_HEADER_4X_CLOCKS_DOMAINS_4_DISPCLK 7
103#define NV_PERF_HEADER_4X_CLOCKS_DOMAINS_4_NUMCLKS 8
104
105#define PERF_CLK_MCLK 0
106#define PERF_CLK_DISPCLK 1
107#define PERF_CLK_GPC2CLK 2
108#define PERF_CLK_HOSTCLK 3
109#define PERF_CLK_LTC2CLK 4
110#define PERF_CLK_SYS2CLK 5
111#define PERF_CLK_HUB2CLK 6
112#define PERF_CLK_LEGCLK 7
113#define PERF_CLK_MSDCLK 8
114#define PERF_CLK_XCLK 9
115#define PERF_CLK_PWRCLK 10
116#define PERF_CLK_XBAR2CLK 11
117#define PERF_CLK_PCIEGENCLK 12
118#define PERF_CLK_NUM 13
119
120#define BOOT_GPC2CLK_MHZ 2581
121
122u32 clk_pmu_vin_load(struct gk20a *g);
123u32 clk_domain_print_vf_table(struct gk20a *g, u32 clkapidomain);
124u32 clk_domain_get_f_or_v(
125 struct gk20a *g,
126 u32 clkapidomain,
127 u16 *pclkmhz,
128 u32 *pvoltuv,
129 u8 railidx
130);
131int clk_get_fll_clks(struct gk20a *g, struct set_fll_clk *fllclk);
132int clk_set_fll_clks(struct gk20a *g, struct set_fll_clk *fllclk);
133int clk_pmu_freq_controller_load(struct gk20a *g, bool bload, u8 bit_idx);
134u32 nvgpu_clk_vf_change_inject_data_fill_gv10x(struct gk20a *g,
135 struct nv_pmu_clk_rpc *rpccall,
136 struct set_fll_clk *setfllclk);
137u32 nvgpu_clk_vf_change_inject_data_fill_gp10x(struct gk20a *g,
138 struct nv_pmu_clk_rpc *rpccall,
139 struct set_fll_clk *setfllclk);
140u32 nvgpu_clk_set_boot_fll_clk_gv10x(struct gk20a *g);
141int nvgpu_clk_set_fll_clk_gv10x(struct gk20a *g);
142int clk_pmu_freq_effective_avg_load(struct gk20a *g, bool bload);
143u32 clk_freq_effective_avg(struct gk20a *g, u32 clkDomainMask);
144#endif /* NVGPU_CLK_H */
diff --git a/include/clk/clk_arb.c b/include/clk/clk_arb.c
new file mode 100644
index 0000000..6cf005c
--- /dev/null
+++ b/include/clk/clk_arb.c
@@ -0,0 +1,1087 @@
1/*
2 * Copyright (c) 2016-2018, 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/bitops.h>
24#include <nvgpu/lock.h>
25#include <nvgpu/kmem.h>
26#include <nvgpu/atomic.h>
27#include <nvgpu/bug.h>
28#include <nvgpu/kref.h>
29#include <nvgpu/log.h>
30#include <nvgpu/barrier.h>
31#include <nvgpu/cond.h>
32#include <nvgpu/list.h>
33#include <nvgpu/clk_arb.h>
34#include <nvgpu/timers.h>
35#include <nvgpu/gk20a.h>
36
37#include "clk/clk.h"
38#include "pstate/pstate.h"
39#include "lpwr/lpwr.h"
40#include "volt/volt.h"
41
42int nvgpu_clk_notification_queue_alloc(struct gk20a *g,
43 struct nvgpu_clk_notification_queue *queue,
44 size_t events_number) {
45 queue->notifications = nvgpu_kcalloc(g, events_number,
46 sizeof(struct nvgpu_clk_notification));
47 if (!queue->notifications)
48 return -ENOMEM;
49 queue->size = events_number;
50
51 nvgpu_atomic_set(&queue->head, 0);
52 nvgpu_atomic_set(&queue->tail, 0);
53
54 return 0;
55}
56
57void nvgpu_clk_notification_queue_free(struct gk20a *g,
58 struct nvgpu_clk_notification_queue *queue) {
59 if (queue->size > 0) {
60 nvgpu_kfree(g, queue->notifications);
61 queue->size = 0;
62 nvgpu_atomic_set(&queue->head, 0);
63 nvgpu_atomic_set(&queue->tail, 0);
64 }
65}
66
67static void nvgpu_clk_arb_queue_notification(struct gk20a *g,
68 struct nvgpu_clk_notification_queue *queue,
69 u32 alarm_mask) {
70
71 u32 queue_index;
72 u64 timestamp;
73
74 queue_index = (nvgpu_atomic_inc_return(&queue->tail)) % queue->size;
75 /* get current timestamp */
76 timestamp = (u64) nvgpu_hr_timestamp();
77
78 queue->notifications[queue_index].timestamp = timestamp;
79 queue->notifications[queue_index].notification = alarm_mask;
80
81}
82
83void nvgpu_clk_arb_set_global_alarm(struct gk20a *g, u32 alarm)
84{
85 struct nvgpu_clk_arb *arb = g->clk_arb;
86
87 u64 current_mask;
88 u32 refcnt;
89 u32 alarm_mask;
90 u64 new_mask;
91
92 do {
93 current_mask = nvgpu_atomic64_read(&arb->alarm_mask);
94 /* atomic operations are strong so they do not need masks */
95
96 refcnt = ((u32) (current_mask >> 32)) + 1;
97 alarm_mask = (u32) (current_mask & ~0) | alarm;
98 new_mask = ((u64) refcnt << 32) | alarm_mask;
99
100 } while (unlikely(current_mask !=
101 (u64)nvgpu_atomic64_cmpxchg(&arb->alarm_mask,
102 current_mask, new_mask)));
103
104 nvgpu_clk_arb_queue_notification(g, &arb->notification_queue, alarm);
105}
106
107
108int nvgpu_clk_arb_update_vf_table(struct nvgpu_clk_arb *arb)
109{
110 struct gk20a *g = arb->g;
111 struct nvgpu_clk_vf_table *table;
112
113 u32 i, j;
114 int status = -EINVAL;
115 u32 gpc2clk_voltuv = 0, mclk_voltuv = 0;
116 u32 gpc2clk_voltuv_sram = 0, mclk_voltuv_sram = 0;
117 u16 clk_cur;
118 u32 num_points;
119
120 struct clk_set_info *p5_info, *p0_info;
121
122 table = NV_ACCESS_ONCE(arb->current_vf_table);
123 /* make flag visible when all data has resolved in the tables */
124 nvgpu_smp_rmb();
125
126 table = (table == &arb->vf_table_pool[0]) ? &arb->vf_table_pool[1] :
127 &arb->vf_table_pool[0];
128
129 /* Get allowed memory ranges */
130 if (g->ops.clk_arb.get_arbiter_clk_range(g, CTRL_CLK_DOMAIN_GPC2CLK,
131 &arb->gpc2clk_min,
132 &arb->gpc2clk_max) < 0) {
133 nvgpu_err(g, "failed to fetch GPC2CLK range");
134 goto exit_vf_table;
135 }
136 if (g->ops.clk_arb.get_arbiter_clk_range(g, CTRL_CLK_DOMAIN_MCLK,
137 &arb->mclk_min,
138 &arb->mclk_max) < 0) {
139 nvgpu_err(g, "failed to fetch MCLK range");
140 goto exit_vf_table;
141 }
142
143 table->gpc2clk_num_points = MAX_F_POINTS;
144 table->mclk_num_points = MAX_F_POINTS;
145
146 if (g->ops.clk.clk_domain_get_f_points(arb->g, CTRL_CLK_DOMAIN_GPC2CLK,
147 &table->gpc2clk_num_points, arb->gpc2clk_f_points)) {
148 nvgpu_err(g, "failed to fetch GPC2CLK frequency points");
149 goto exit_vf_table;
150 }
151
152 if (g->ops.clk.clk_domain_get_f_points(arb->g, CTRL_CLK_DOMAIN_MCLK,
153 &table->mclk_num_points, arb->mclk_f_points)) {
154 nvgpu_err(g, "failed to fetch MCLK frequency points");
155 goto exit_vf_table;
156 }
157 if (!table->mclk_num_points || !table->gpc2clk_num_points) {
158 nvgpu_err(g, "empty queries to f points mclk %d gpc2clk %d",
159 table->mclk_num_points, table->gpc2clk_num_points);
160 status = -EINVAL;
161 goto exit_vf_table;
162 }
163
164 memset(table->mclk_points, 0,
165 table->mclk_num_points*sizeof(struct nvgpu_clk_vf_point));
166 memset(table->gpc2clk_points, 0,
167 table->gpc2clk_num_points*sizeof(struct nvgpu_clk_vf_point));
168
169 p5_info = pstate_get_clk_set_info(g,
170 CTRL_PERF_PSTATE_P5, clkwhich_mclk);
171 if (!p5_info) {
172 nvgpu_err(g, "failed to get MCLK P5 info");
173 goto exit_vf_table;
174 }
175 p0_info = pstate_get_clk_set_info(g,
176 CTRL_PERF_PSTATE_P0, clkwhich_mclk);
177 if (!p0_info) {
178 nvgpu_err(g, "failed to get MCLK P0 info");
179 goto exit_vf_table;
180 }
181
182 for (i = 0, j = 0, num_points = 0, clk_cur = 0;
183 i < table->mclk_num_points; i++) {
184
185 if ((arb->mclk_f_points[i] >= arb->mclk_min) &&
186 (arb->mclk_f_points[i] <= arb->mclk_max) &&
187 (arb->mclk_f_points[i] != clk_cur)) {
188
189 table->mclk_points[j].mem_mhz = arb->mclk_f_points[i];
190 mclk_voltuv = mclk_voltuv_sram = 0;
191
192 status = clk_domain_get_f_or_v(g, CTRL_CLK_DOMAIN_MCLK,
193 &table->mclk_points[j].mem_mhz, &mclk_voltuv,
194 CTRL_VOLT_DOMAIN_LOGIC);
195 if (status < 0) {
196 nvgpu_err(g,
197 "failed to get MCLK LOGIC voltage");
198 goto exit_vf_table;
199 }
200 status = clk_domain_get_f_or_v(g, CTRL_CLK_DOMAIN_MCLK,
201 &table->mclk_points[j].mem_mhz,
202 &mclk_voltuv_sram,
203 CTRL_VOLT_DOMAIN_SRAM);
204 if (status < 0) {
205 nvgpu_err(g, "failed to get MCLK SRAM voltage");
206 goto exit_vf_table;
207 }
208
209 table->mclk_points[j].uvolt = mclk_voltuv;
210 table->mclk_points[j].uvolt_sram = mclk_voltuv_sram;
211 clk_cur = table->mclk_points[j].mem_mhz;
212
213 if ((clk_cur >= p5_info->min_mhz) &&
214 (clk_cur <= p5_info->max_mhz))
215 VF_POINT_SET_PSTATE_SUPPORTED(
216 &table->mclk_points[j],
217 CTRL_PERF_PSTATE_P5);
218 if ((clk_cur >= p0_info->min_mhz) &&
219 (clk_cur <= p0_info->max_mhz))
220 VF_POINT_SET_PSTATE_SUPPORTED(
221 &table->mclk_points[j],
222 CTRL_PERF_PSTATE_P0);
223
224 j++;
225 num_points++;
226
227 }
228 }
229 table->mclk_num_points = num_points;
230
231 p5_info = pstate_get_clk_set_info(g,
232 CTRL_PERF_PSTATE_P5, clkwhich_gpc2clk);
233 if (!p5_info) {
234 status = -EINVAL;
235 nvgpu_err(g, "failed to get GPC2CLK P5 info");
236 goto exit_vf_table;
237 }
238
239 p0_info = pstate_get_clk_set_info(g,
240 CTRL_PERF_PSTATE_P0, clkwhich_gpc2clk);
241 if (!p0_info) {
242 status = -EINVAL;
243 nvgpu_err(g, "failed to get GPC2CLK P0 info");
244 goto exit_vf_table;
245 }
246
247 /* GPC2CLK needs to be checked in two passes. The first determines the
248 * relationships between GPC2CLK, SYS2CLK and XBAR2CLK, while the
249 * second verifies that the clocks minimum is satisfied and sets
250 * the voltages
251 */
252 for (i = 0, j = 0, num_points = 0, clk_cur = 0;
253 i < table->gpc2clk_num_points; i++) {
254 struct set_fll_clk setfllclk;
255
256 if ((arb->gpc2clk_f_points[i] >= arb->gpc2clk_min) &&
257 (arb->gpc2clk_f_points[i] <= arb->gpc2clk_max) &&
258 (arb->gpc2clk_f_points[i] != clk_cur)) {
259
260 table->gpc2clk_points[j].gpc_mhz =
261 arb->gpc2clk_f_points[i];
262 setfllclk.gpc2clkmhz = arb->gpc2clk_f_points[i];
263 status = clk_get_fll_clks(g, &setfllclk);
264 if (status < 0) {
265 nvgpu_err(g,
266 "failed to get GPC2CLK slave clocks");
267 goto exit_vf_table;
268 }
269
270 table->gpc2clk_points[j].sys_mhz =
271 setfllclk.sys2clkmhz;
272 table->gpc2clk_points[j].xbar_mhz =
273 setfllclk.xbar2clkmhz;
274
275 clk_cur = table->gpc2clk_points[j].gpc_mhz;
276
277 if ((clk_cur >= p5_info->min_mhz) &&
278 (clk_cur <= p5_info->max_mhz))
279 VF_POINT_SET_PSTATE_SUPPORTED(
280 &table->gpc2clk_points[j],
281 CTRL_PERF_PSTATE_P5);
282 if ((clk_cur >= p0_info->min_mhz) &&
283 (clk_cur <= p0_info->max_mhz))
284 VF_POINT_SET_PSTATE_SUPPORTED(
285 &table->gpc2clk_points[j],
286 CTRL_PERF_PSTATE_P0);
287
288 j++;
289 num_points++;
290 }
291 }
292 table->gpc2clk_num_points = num_points;
293
294 /* Second pass */
295 for (i = 0, j = 0; i < table->gpc2clk_num_points; i++) {
296
297 u16 alt_gpc2clk = table->gpc2clk_points[i].gpc_mhz;
298
299 gpc2clk_voltuv = gpc2clk_voltuv_sram = 0;
300
301 /* Check sysclk */
302 p5_info = pstate_get_clk_set_info(g,
303 VF_POINT_GET_PSTATE(&table->gpc2clk_points[i]),
304 clkwhich_sys2clk);
305 if (!p5_info) {
306 status = -EINVAL;
307 nvgpu_err(g, "failed to get SYS2CLK P5 info");
308 goto exit_vf_table;
309 }
310
311 /* sys2clk below clk min, need to find correct clock */
312 if (table->gpc2clk_points[i].sys_mhz < p5_info->min_mhz) {
313 for (j = i + 1; j < table->gpc2clk_num_points; j++) {
314
315 if (table->gpc2clk_points[j].sys_mhz >=
316 p5_info->min_mhz) {
317
318
319 table->gpc2clk_points[i].sys_mhz =
320 p5_info->min_mhz;
321
322 alt_gpc2clk = alt_gpc2clk <
323 table->gpc2clk_points[j].
324 gpc_mhz ?
325 table->gpc2clk_points[j].
326 gpc_mhz :
327 alt_gpc2clk;
328 break;
329 }
330 }
331 /* no VF exists that satisfies condition */
332 if (j == table->gpc2clk_num_points) {
333 nvgpu_err(g, "NO SYS2CLK VF point possible");
334 status = -EINVAL;
335 goto exit_vf_table;
336 }
337 }
338
339 /* Check xbarclk */
340 p5_info = pstate_get_clk_set_info(g,
341 VF_POINT_GET_PSTATE(&table->gpc2clk_points[i]),
342 clkwhich_xbar2clk);
343 if (!p5_info) {
344 status = -EINVAL;
345 nvgpu_err(g, "failed to get SYS2CLK P5 info");
346 goto exit_vf_table;
347 }
348
349 /* xbar2clk below clk min, need to find correct clock */
350 if (table->gpc2clk_points[i].xbar_mhz < p5_info->min_mhz) {
351 for (j = i; j < table->gpc2clk_num_points; j++) {
352 if (table->gpc2clk_points[j].xbar_mhz >=
353 p5_info->min_mhz) {
354
355 table->gpc2clk_points[i].xbar_mhz =
356 p5_info->min_mhz;
357
358 alt_gpc2clk = alt_gpc2clk <
359 table->gpc2clk_points[j].
360 gpc_mhz ?
361 table->gpc2clk_points[j].
362 gpc_mhz :
363 alt_gpc2clk;
364 break;
365 }
366 }
367 /* no VF exists that satisfies condition */
368 if (j == table->gpc2clk_num_points) {
369 status = -EINVAL;
370 nvgpu_err(g, "NO XBAR2CLK VF point possible");
371
372 goto exit_vf_table;
373 }
374 }
375
376 /* Calculate voltages */
377 status = clk_domain_get_f_or_v(g, CTRL_CLK_DOMAIN_GPC2CLK,
378 &alt_gpc2clk, &gpc2clk_voltuv,
379 CTRL_VOLT_DOMAIN_LOGIC);
380 if (status < 0) {
381 nvgpu_err(g, "failed to get GPC2CLK LOGIC voltage");
382 goto exit_vf_table;
383 }
384
385 status = clk_domain_get_f_or_v(g, CTRL_CLK_DOMAIN_GPC2CLK,
386 &alt_gpc2clk,
387 &gpc2clk_voltuv_sram,
388 CTRL_VOLT_DOMAIN_SRAM);
389 if (status < 0) {
390 nvgpu_err(g, "failed to get GPC2CLK SRAM voltage");
391 goto exit_vf_table;
392 }
393
394 table->gpc2clk_points[i].uvolt = gpc2clk_voltuv;
395 table->gpc2clk_points[i].uvolt_sram = gpc2clk_voltuv_sram;
396 }
397
398 /* make table visible when all data has resolved in the tables */
399 nvgpu_smp_wmb();
400 arb->current_vf_table = table;
401
402exit_vf_table:
403
404 if (status < 0)
405 nvgpu_clk_arb_set_global_alarm(g,
406 EVENT(ALARM_VF_TABLE_UPDATE_FAILED));
407 nvgpu_clk_arb_worker_enqueue(g, &arb->update_arb_work_item);
408
409 return status;
410}
411
412
413static void nvgpu_clk_arb_run_vf_table_cb(struct nvgpu_clk_arb *arb)
414{
415 struct gk20a *g = arb->g;
416 u32 err;
417
418 /* get latest vf curve from pmu */
419 err = clk_vf_point_cache(g);
420 if (err) {
421 nvgpu_err(g, "failed to cache VF table");
422 nvgpu_clk_arb_set_global_alarm(g,
423 EVENT(ALARM_VF_TABLE_UPDATE_FAILED));
424 nvgpu_clk_arb_worker_enqueue(g, &arb->update_arb_work_item);
425
426 return;
427 }
428 nvgpu_clk_arb_update_vf_table(arb);
429}
430
431u32 nvgpu_clk_arb_notify(struct nvgpu_clk_dev *dev,
432 struct nvgpu_clk_arb_target *target,
433 u32 alarm) {
434
435 struct nvgpu_clk_session *session = dev->session;
436 struct nvgpu_clk_arb *arb = session->g->clk_arb;
437 struct nvgpu_clk_notification *notification;
438
439 u32 queue_alarm_mask = 0;
440 u32 enabled_mask = 0;
441 u32 new_alarms_reported = 0;
442 u32 poll_mask = 0;
443 u32 tail, head;
444 u32 queue_index;
445 size_t size;
446 int index;
447
448 enabled_mask = nvgpu_atomic_read(&dev->enabled_mask);
449 size = arb->notification_queue.size;
450
451 /* queue global arbiter notifications in buffer */
452 do {
453 tail = nvgpu_atomic_read(&arb->notification_queue.tail);
454 /* copy items to the queue */
455 queue_index = nvgpu_atomic_read(&dev->queue.tail);
456 head = dev->arb_queue_head;
457 head = (tail - head) < arb->notification_queue.size ?
458 head : tail - arb->notification_queue.size;
459
460 for (index = head; _WRAPGTEQ(tail, index); index++) {
461 u32 alarm_detected;
462
463 notification = &arb->notification_queue.
464 notifications[(index+1) % size];
465 alarm_detected =
466 NV_ACCESS_ONCE(notification->notification);
467
468 if (!(enabled_mask & alarm_detected))
469 continue;
470
471 queue_index++;
472 dev->queue.notifications[
473 queue_index % dev->queue.size].timestamp =
474 NV_ACCESS_ONCE(notification->timestamp);
475
476 dev->queue.notifications[
477 queue_index % dev->queue.size].notification =
478 alarm_detected;
479
480 queue_alarm_mask |= alarm_detected;
481 }
482 } while (unlikely(nvgpu_atomic_read(&arb->notification_queue.tail) !=
483 (int)tail));
484
485 nvgpu_atomic_set(&dev->queue.tail, queue_index);
486 /* update the last notification we processed from global queue */
487
488 dev->arb_queue_head = tail;
489
490 /* Check if current session targets are met */
491 if (enabled_mask & EVENT(ALARM_LOCAL_TARGET_VF_NOT_POSSIBLE)) {
492 if ((target->gpc2clk < session->target->gpc2clk)
493 || (target->mclk < session->target->mclk)) {
494
495 poll_mask |= (NVGPU_POLLIN | NVGPU_POLLPRI);
496 nvgpu_clk_arb_queue_notification(arb->g, &dev->queue,
497 EVENT(ALARM_LOCAL_TARGET_VF_NOT_POSSIBLE));
498 }
499 }
500
501 /* Check if there is a new VF update */
502 if (queue_alarm_mask & EVENT(VF_UPDATE))
503 poll_mask |= (NVGPU_POLLIN | NVGPU_POLLRDNORM);
504
505 /* Notify sticky alarms that were not reported on previous run*/
506 new_alarms_reported = (queue_alarm_mask |
507 (alarm & ~dev->alarms_reported & queue_alarm_mask));
508
509 if (new_alarms_reported & ~LOCAL_ALARM_MASK) {
510 /* check that we are not re-reporting */
511 if (new_alarms_reported & EVENT(ALARM_GPU_LOST))
512 poll_mask |= NVGPU_POLLHUP;
513
514 poll_mask |= (NVGPU_POLLIN | NVGPU_POLLPRI);
515 /* On next run do not report global alarms that were already
516 * reported, but report SHUTDOWN always
517 */
518 dev->alarms_reported = new_alarms_reported & ~LOCAL_ALARM_MASK &
519 ~EVENT(ALARM_GPU_LOST);
520 }
521
522 if (poll_mask) {
523 nvgpu_atomic_set(&dev->poll_mask, poll_mask);
524 nvgpu_clk_arb_event_post_event(dev);
525 }
526
527 return new_alarms_reported;
528}
529
530void nvgpu_clk_arb_clear_global_alarm(struct gk20a *g, u32 alarm)
531{
532 struct nvgpu_clk_arb *arb = g->clk_arb;
533
534 u64 current_mask;
535 u32 refcnt;
536 u32 alarm_mask;
537 u64 new_mask;
538
539 do {
540 current_mask = nvgpu_atomic64_read(&arb->alarm_mask);
541 /* atomic operations are strong so they do not need masks */
542
543 refcnt = ((u32) (current_mask >> 32)) + 1;
544 alarm_mask = (u32) (current_mask & ~alarm);
545 new_mask = ((u64) refcnt << 32) | alarm_mask;
546
547 } while (unlikely(current_mask !=
548 (u64)nvgpu_atomic64_cmpxchg(&arb->alarm_mask,
549 current_mask, new_mask)));
550}
551
552/*
553 * Process one scheduled work item.
554 */
555static void nvgpu_clk_arb_worker_process_item(
556 struct nvgpu_clk_arb_work_item *work_item)
557{
558 struct gk20a *g = work_item->arb->g;
559
560 clk_arb_dbg(g, " ");
561
562 if (work_item->item_type == CLK_ARB_WORK_UPDATE_VF_TABLE)
563 nvgpu_clk_arb_run_vf_table_cb(work_item->arb);
564 else if (work_item->item_type == CLK_ARB_WORK_UPDATE_ARB)
565 g->ops.clk_arb.clk_arb_run_arbiter_cb(work_item->arb);
566}
567
568/**
569 * Tell the worker that one more work needs to be done.
570 *
571 * Increase the work counter to synchronize the worker with the new work. Wake
572 * up the worker. If the worker was already running, it will handle this work
573 * before going to sleep.
574 */
575static int nvgpu_clk_arb_worker_wakeup(struct gk20a *g)
576{
577 int put;
578
579 clk_arb_dbg(g, " ");
580
581 put = nvgpu_atomic_inc_return(&g->clk_arb_worker.put);
582 nvgpu_cond_signal_interruptible(&g->clk_arb_worker.wq);
583
584 return put;
585}
586
587/**
588 * Test if there is some work pending.
589 *
590 * This is a pair for nvgpu_clk_arb_worker_wakeup to be called from the
591 * worker. The worker has an internal work counter which is incremented once
592 * per finished work item. This is compared with the number of queued jobs.
593 */
594static bool nvgpu_clk_arb_worker_pending(struct gk20a *g, int get)
595{
596 bool pending = nvgpu_atomic_read(&g->clk_arb_worker.put) != get;
597
598 /* We don't need barriers because they are implicit in locking */
599 return pending;
600}
601
602/**
603 * Process the queued works for the worker thread serially.
604 *
605 * Flush all the work items in the queue one by one. This may block timeout
606 * handling for a short while, as these are serialized.
607 */
608static void nvgpu_clk_arb_worker_process(struct gk20a *g, int *get)
609{
610
611 while (nvgpu_clk_arb_worker_pending(g, *get)) {
612 struct nvgpu_clk_arb_work_item *work_item = NULL;
613
614 nvgpu_spinlock_acquire(&g->clk_arb_worker.items_lock);
615 if (!nvgpu_list_empty(&g->clk_arb_worker.items)) {
616 work_item = nvgpu_list_first_entry(&g->clk_arb_worker.items,
617 nvgpu_clk_arb_work_item, worker_item);
618 nvgpu_list_del(&work_item->worker_item);
619 }
620 nvgpu_spinlock_release(&g->clk_arb_worker.items_lock);
621
622 if (!work_item) {
623 /*
624 * Woke up for some other reason, but there are no
625 * other reasons than a work item added in the items list
626 * currently, so warn and ack the message.
627 */
628 nvgpu_warn(g, "Spurious worker event!");
629 ++*get;
630 break;
631 }
632
633 nvgpu_clk_arb_worker_process_item(work_item);
634 ++*get;
635 }
636}
637
638/*
639 * Process all work items found in the clk arbiter work queue.
640 */
641static int nvgpu_clk_arb_poll_worker(void *arg)
642{
643 struct gk20a *g = (struct gk20a *)arg;
644 struct gk20a_worker *worker = &g->clk_arb_worker;
645 int get = 0;
646
647 clk_arb_dbg(g, " ");
648
649 while (!nvgpu_thread_should_stop(&worker->poll_task)) {
650 int ret;
651
652 ret = NVGPU_COND_WAIT_INTERRUPTIBLE(
653 &worker->wq,
654 nvgpu_clk_arb_worker_pending(g, get), 0);
655
656 if (nvgpu_thread_should_stop(&worker->poll_task)) {
657 break;
658 }
659
660 if (ret == 0)
661 nvgpu_clk_arb_worker_process(g, &get);
662 }
663 return 0;
664}
665
666static int __nvgpu_clk_arb_worker_start(struct gk20a *g)
667{
668 char thread_name[64];
669 int err = 0;
670
671 if (nvgpu_thread_is_running(&g->clk_arb_worker.poll_task))
672 return err;
673
674 nvgpu_mutex_acquire(&g->clk_arb_worker.start_lock);
675
676 /*
677 * Mutexes have implicit barriers, so there is no risk of a thread
678 * having a stale copy of the poll_task variable as the call to
679 * thread_is_running is volatile
680 */
681
682 if (nvgpu_thread_is_running(&g->clk_arb_worker.poll_task)) {
683 nvgpu_mutex_release(&g->clk_arb_worker.start_lock);
684 return err;
685 }
686
687 snprintf(thread_name, sizeof(thread_name),
688 "nvgpu_clk_arb_poll_%s", g->name);
689
690 err = nvgpu_thread_create(&g->clk_arb_worker.poll_task, g,
691 nvgpu_clk_arb_poll_worker, thread_name);
692
693 nvgpu_mutex_release(&g->clk_arb_worker.start_lock);
694 return err;
695}
696
697/**
698 * Append a work item to the worker's list.
699 *
700 * This adds work item to the end of the list and wakes the worker
701 * up immediately. If the work item already existed in the list, it's not added,
702 * because in that case it has been scheduled already but has not yet been
703 * processed.
704 */
705void nvgpu_clk_arb_worker_enqueue(struct gk20a *g,
706 struct nvgpu_clk_arb_work_item *work_item)
707{
708 clk_arb_dbg(g, " ");
709
710 /*
711 * Warn if worker thread cannot run
712 */
713 if (WARN_ON(__nvgpu_clk_arb_worker_start(g))) {
714 nvgpu_warn(g, "clk arb worker cannot run!");
715 return;
716 }
717
718 nvgpu_spinlock_acquire(&g->clk_arb_worker.items_lock);
719 if (!nvgpu_list_empty(&work_item->worker_item)) {
720 /*
721 * Already queued, so will get processed eventually.
722 * The worker is probably awake already.
723 */
724 nvgpu_spinlock_release(&g->clk_arb_worker.items_lock);
725 return;
726 }
727 nvgpu_list_add_tail(&work_item->worker_item, &g->clk_arb_worker.items);
728 nvgpu_spinlock_release(&g->clk_arb_worker.items_lock);
729
730 nvgpu_clk_arb_worker_wakeup(g);
731}
732
733/**
734 * Initialize the clk arb worker's metadata and start the background thread.
735 */
736int nvgpu_clk_arb_worker_init(struct gk20a *g)
737{
738 int err;
739
740 nvgpu_atomic_set(&g->clk_arb_worker.put, 0);
741 nvgpu_cond_init(&g->clk_arb_worker.wq);
742 nvgpu_init_list_node(&g->clk_arb_worker.items);
743 nvgpu_spinlock_init(&g->clk_arb_worker.items_lock);
744 err = nvgpu_mutex_init(&g->clk_arb_worker.start_lock);
745 if (err)
746 goto error_check;
747
748 err = __nvgpu_clk_arb_worker_start(g);
749error_check:
750 if (err) {
751 nvgpu_err(g, "failed to start clk arb poller thread");
752 return err;
753 }
754 return 0;
755}
756
757int nvgpu_clk_arb_init_arbiter(struct gk20a *g)
758{
759 int err = 0;
760
761 if (!g->ops.clk.support_clk_freq_controller ||
762 !g->ops.clk_arb.get_arbiter_clk_domains) {
763 return 0;
764 }
765
766 nvgpu_mutex_acquire(&g->clk_arb_enable_lock);
767
768 err = g->ops.clk_arb.arbiter_clk_init(g);
769
770 nvgpu_mutex_release(&g->clk_arb_enable_lock);
771
772 return err;
773}
774
775bool nvgpu_clk_arb_has_active_req(struct gk20a *g)
776{
777 return (nvgpu_atomic_read(&g->clk_arb_global_nr) > 0);
778}
779
780void nvgpu_clk_arb_send_thermal_alarm(struct gk20a *g)
781{
782 nvgpu_clk_arb_schedule_alarm(g,
783 (0x1UL << NVGPU_EVENT_ALARM_THERMAL_ABOVE_THRESHOLD));
784}
785
786void nvgpu_clk_arb_schedule_alarm(struct gk20a *g, u32 alarm)
787{
788 struct nvgpu_clk_arb *arb = g->clk_arb;
789
790 nvgpu_clk_arb_set_global_alarm(g, alarm);
791 nvgpu_clk_arb_worker_enqueue(g, &arb->update_arb_work_item);
792}
793
794static void nvgpu_clk_arb_worker_deinit(struct gk20a *g)
795{
796 nvgpu_atomic_inc(&g->clk_arb_worker.put);
797
798 nvgpu_mutex_acquire(&g->clk_arb_worker.start_lock);
799 nvgpu_thread_stop(&g->clk_arb_worker.poll_task);
800 nvgpu_mutex_release(&g->clk_arb_worker.start_lock);
801}
802
803void nvgpu_clk_arb_cleanup_arbiter(struct gk20a *g)
804{
805 struct nvgpu_clk_arb *arb = g->clk_arb;
806
807 nvgpu_mutex_acquire(&g->clk_arb_enable_lock);
808
809 if (arb) {
810 nvgpu_clk_arb_worker_deinit(g);
811 g->ops.clk_arb.clk_arb_cleanup(g->clk_arb);
812 }
813
814 nvgpu_mutex_release(&g->clk_arb_enable_lock);
815}
816
817int nvgpu_clk_arb_init_session(struct gk20a *g,
818 struct nvgpu_clk_session **_session)
819{
820 struct nvgpu_clk_arb *arb = g->clk_arb;
821 struct nvgpu_clk_session *session = *(_session);
822
823 clk_arb_dbg(g, " ");
824
825 if (!g->ops.clk.support_clk_freq_controller ||
826 !g->ops.clk_arb.get_arbiter_clk_domains) {
827 return 0;
828 }
829
830 session = nvgpu_kzalloc(g, sizeof(struct nvgpu_clk_session));
831 if (!session)
832 return -ENOMEM;
833 session->g = g;
834
835 nvgpu_ref_init(&session->refcount);
836
837 session->zombie = false;
838 session->target_pool[0].pstate = CTRL_PERF_PSTATE_P8;
839 /* make sure that the initialization of the pool is visible
840 * before the update
841 */
842 nvgpu_smp_wmb();
843 session->target = &session->target_pool[0];
844
845 nvgpu_init_list_node(&session->targets);
846 nvgpu_spinlock_init(&session->session_lock);
847
848 nvgpu_spinlock_acquire(&arb->sessions_lock);
849 nvgpu_list_add_tail(&session->link, &arb->sessions);
850 nvgpu_spinlock_release(&arb->sessions_lock);
851
852 *_session = session;
853
854 return 0;
855}
856
857void nvgpu_clk_arb_free_fd(struct nvgpu_ref *refcount)
858{
859 struct nvgpu_clk_dev *dev = container_of(refcount,
860 struct nvgpu_clk_dev, refcount);
861 struct nvgpu_clk_session *session = dev->session;
862 struct gk20a *g = session->g;
863
864 nvgpu_clk_notification_queue_free(g, &dev->queue);
865
866 nvgpu_atomic_dec(&g->clk_arb_global_nr);
867 nvgpu_kfree(g, dev);
868}
869
870void nvgpu_clk_arb_free_session(struct nvgpu_ref *refcount)
871{
872 struct nvgpu_clk_session *session = container_of(refcount,
873 struct nvgpu_clk_session, refcount);
874 struct nvgpu_clk_arb *arb = session->g->clk_arb;
875 struct gk20a *g = session->g;
876 struct nvgpu_clk_dev *dev, *tmp;
877
878 clk_arb_dbg(g, " ");
879
880 if (arb) {
881 nvgpu_spinlock_acquire(&arb->sessions_lock);
882 nvgpu_list_del(&session->link);
883 nvgpu_spinlock_release(&arb->sessions_lock);
884 }
885
886 nvgpu_spinlock_acquire(&session->session_lock);
887 nvgpu_list_for_each_entry_safe(dev, tmp, &session->targets,
888 nvgpu_clk_dev, node) {
889 nvgpu_ref_put(&dev->refcount, nvgpu_clk_arb_free_fd);
890 nvgpu_list_del(&dev->node);
891 }
892 nvgpu_spinlock_release(&session->session_lock);
893
894 nvgpu_kfree(g, session);
895}
896
897void nvgpu_clk_arb_release_session(struct gk20a *g,
898 struct nvgpu_clk_session *session)
899{
900 struct nvgpu_clk_arb *arb = g->clk_arb;
901
902 clk_arb_dbg(g, " ");
903
904 session->zombie = true;
905 nvgpu_ref_put(&session->refcount, nvgpu_clk_arb_free_session);
906 if (arb)
907 nvgpu_clk_arb_worker_enqueue(g, &arb->update_arb_work_item);
908}
909
910void nvgpu_clk_arb_schedule_vf_table_update(struct gk20a *g)
911{
912 struct nvgpu_clk_arb *arb = g->clk_arb;
913
914 nvgpu_clk_arb_worker_enqueue(g, &arb->update_vf_table_work_item);
915}
916
917/* This function is inherently unsafe to call while arbiter is running
918 * arbiter must be blocked before calling this function
919 */
920int nvgpu_clk_arb_get_current_pstate(struct gk20a *g)
921{
922 return NV_ACCESS_ONCE(g->clk_arb->actual->pstate);
923}
924
925void nvgpu_clk_arb_pstate_change_lock(struct gk20a *g, bool lock)
926{
927 struct nvgpu_clk_arb *arb = g->clk_arb;
928
929 if (lock)
930 nvgpu_mutex_acquire(&arb->pstate_lock);
931 else
932 nvgpu_mutex_release(&arb->pstate_lock);
933}
934
935bool nvgpu_clk_arb_is_valid_domain(struct gk20a *g, u32 api_domain)
936{
937 u32 clk_domains = g->ops.clk_arb.get_arbiter_clk_domains(g);
938
939 switch (api_domain) {
940 case NVGPU_CLK_DOMAIN_MCLK:
941 return (clk_domains & CTRL_CLK_DOMAIN_MCLK) != 0;
942
943 case NVGPU_CLK_DOMAIN_GPCCLK:
944 return (clk_domains & CTRL_CLK_DOMAIN_GPC2CLK) != 0;
945
946 default:
947 return false;
948 }
949}
950
951int nvgpu_clk_arb_get_arbiter_clk_range(struct gk20a *g, u32 api_domain,
952 u16 *min_mhz, u16 *max_mhz)
953{
954 int ret;
955
956 switch (api_domain) {
957 case NVGPU_CLK_DOMAIN_MCLK:
958 ret = g->ops.clk_arb.get_arbiter_clk_range(g,
959 CTRL_CLK_DOMAIN_MCLK, min_mhz, max_mhz);
960 return ret;
961
962 case NVGPU_CLK_DOMAIN_GPCCLK:
963 ret = g->ops.clk_arb.get_arbiter_clk_range(g,
964 CTRL_CLK_DOMAIN_GPC2CLK, min_mhz, max_mhz);
965 if (!ret) {
966 *min_mhz /= 2;
967 *max_mhz /= 2;
968 }
969 return ret;
970
971 default:
972 return -EINVAL;
973 }
974}
975
976int nvgpu_clk_arb_get_arbiter_clk_f_points(struct gk20a *g,
977 u32 api_domain, u32 *max_points, u16 *fpoints)
978{
979 int err;
980 u32 i;
981
982 switch (api_domain) {
983 case NVGPU_CLK_DOMAIN_GPCCLK:
984 err = g->ops.clk_arb.get_arbiter_f_points(g,
985 CTRL_CLK_DOMAIN_GPC2CLK, max_points, fpoints);
986 if (err || !fpoints)
987 return err;
988 for (i = 0; i < *max_points; i++)
989 fpoints[i] /= 2;
990 return 0;
991 case NVGPU_CLK_DOMAIN_MCLK:
992 return g->ops.clk_arb.get_arbiter_f_points(g,
993 CTRL_CLK_DOMAIN_MCLK, max_points, fpoints);
994 default:
995 return -EINVAL;
996 }
997}
998
999int nvgpu_clk_arb_get_session_target_mhz(struct nvgpu_clk_session *session,
1000 u32 api_domain, u16 *freq_mhz)
1001{
1002 int err = 0;
1003 struct nvgpu_clk_arb_target *target = session->target;
1004
1005 if (!nvgpu_clk_arb_is_valid_domain(session->g, api_domain)) {
1006 return -EINVAL;
1007 }
1008
1009 switch (api_domain) {
1010 case NVGPU_CLK_DOMAIN_MCLK:
1011 *freq_mhz = target->mclk;
1012 break;
1013
1014 case NVGPU_CLK_DOMAIN_GPCCLK:
1015 *freq_mhz = target->gpc2clk / 2ULL;
1016 break;
1017
1018 default:
1019 *freq_mhz = 0;
1020 err = -EINVAL;
1021 }
1022 return err;
1023}
1024
1025int nvgpu_clk_arb_get_arbiter_actual_mhz(struct gk20a *g,
1026 u32 api_domain, u16 *freq_mhz)
1027{
1028 struct nvgpu_clk_arb *arb = g->clk_arb;
1029 int err = 0;
1030 struct nvgpu_clk_arb_target *actual = arb->actual;
1031
1032 if (!nvgpu_clk_arb_is_valid_domain(g, api_domain)) {
1033 return -EINVAL;
1034 }
1035
1036 switch (api_domain) {
1037 case NVGPU_CLK_DOMAIN_MCLK:
1038 *freq_mhz = actual->mclk;
1039 break;
1040
1041 case NVGPU_CLK_DOMAIN_GPCCLK:
1042 *freq_mhz = actual->gpc2clk / 2ULL;
1043 break;
1044
1045 default:
1046 *freq_mhz = 0;
1047 err = -EINVAL;
1048 }
1049 return err;
1050}
1051
1052unsigned long nvgpu_clk_measure_freq(struct gk20a *g, u32 api_domain)
1053{
1054 unsigned long freq = 0UL;
1055
1056 switch (api_domain) {
1057 case CTRL_CLK_DOMAIN_GPC2CLK:
1058 freq = g->ops.clk.get_rate(g, CTRL_CLK_DOMAIN_GPCCLK) * 2UL;
1059 break;
1060 default:
1061 break;
1062 }
1063 return freq;
1064}
1065
1066int nvgpu_clk_arb_get_arbiter_effective_mhz(struct gk20a *g,
1067 u32 api_domain, u16 *freq_mhz)
1068{
1069 if (!nvgpu_clk_arb_is_valid_domain(g, api_domain)) {
1070 return -EINVAL;
1071 }
1072
1073 switch (api_domain) {
1074 case NVGPU_CLK_DOMAIN_MCLK:
1075 *freq_mhz = g->ops.clk.measure_freq(g, CTRL_CLK_DOMAIN_MCLK) /
1076 1000000ULL;
1077 return 0;
1078
1079 case NVGPU_CLK_DOMAIN_GPCCLK:
1080 *freq_mhz = g->ops.clk.measure_freq(g,
1081 CTRL_CLK_DOMAIN_GPC2CLK) / 2000000ULL;
1082 return 0;
1083
1084 default:
1085 return -EINVAL;
1086 }
1087}
diff --git a/include/clk/clk_domain.c b/include/clk/clk_domain.c
new file mode 100644
index 0000000..3b64f51
--- /dev/null
+++ b/include/clk/clk_domain.c
@@ -0,0 +1,1666 @@
1/*
2 * Copyright (c) 2016-2018, 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/gk20a.h>
25
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 int devinit_get_clocks_table(struct gk20a *g,
37 struct clk_domains *pdomainobjs);
38
39static int clk_domain_pmudatainit_super(struct gk20a *g, struct boardobj
40 *board_obj_ptr, struct nv_pmu_boardobj *ppmudata);
41
42static struct vbios_clocks_table_1x_hal_clock_entry
43 vbiosclktbl1xhalentry_gp[] = {
44 { clkwhich_gpc2clk, true, 1, },
45 { clkwhich_xbar2clk, true, 1, },
46 { clkwhich_mclk, false, 1, },
47 { clkwhich_sys2clk, true, 1, },
48 { clkwhich_hub2clk, false, 1, },
49 { clkwhich_nvdclk, false, 1, },
50 { clkwhich_pwrclk, false, 1, },
51 { clkwhich_dispclk, false, 1, },
52 { clkwhich_pciegenclk, false, 1, }
53};
54/*
55 * Updated from RM devinit_clock.c
56 * GV100 is 0x03 and
57 * GP10x is 0x02 in clocks_hal.
58 */
59static struct vbios_clocks_table_1x_hal_clock_entry
60 vbiosclktbl1xhalentry_gv[] = {
61 { clkwhich_gpcclk, true, 2, },
62 { clkwhich_xbarclk, true, 1, },
63 { clkwhich_mclk, false, 1, },
64 { clkwhich_sysclk, true, 1, },
65 { clkwhich_hubclk, false, 1, },
66 { clkwhich_nvdclk, true, 1, },
67 { clkwhich_pwrclk, false, 1, },
68 { clkwhich_dispclk, false, 1, },
69 { clkwhich_pciegenclk, false, 1, },
70 { clkwhich_hostclk, true, 1, }
71};
72
73static u32 clktranslatehalmumsettoapinumset(u32 clkhaldomains)
74{
75 u32 clkapidomains = 0;
76
77 if (clkhaldomains & BIT(clkwhich_gpcclk)) {
78 clkapidomains |= CTRL_CLK_DOMAIN_GPCCLK;
79 }
80 if (clkhaldomains & BIT(clkwhich_xbarclk)) {
81 clkapidomains |= CTRL_CLK_DOMAIN_XBARCLK;
82 }
83 if (clkhaldomains & BIT(clkwhich_sysclk)) {
84 clkapidomains |= CTRL_CLK_DOMAIN_SYSCLK;
85 }
86 if (clkhaldomains & BIT(clkwhich_hubclk)) {
87 clkapidomains |= CTRL_CLK_DOMAIN_HUBCLK;
88 }
89 if (clkhaldomains & BIT(clkwhich_hostclk)) {
90 clkapidomains |= CTRL_CLK_DOMAIN_HOSTCLK;
91 }
92 if (clkhaldomains & BIT(clkwhich_gpc2clk)) {
93 clkapidomains |= CTRL_CLK_DOMAIN_GPC2CLK;
94 }
95 if (clkhaldomains & BIT(clkwhich_xbar2clk)) {
96 clkapidomains |= CTRL_CLK_DOMAIN_XBAR2CLK;
97 }
98 if (clkhaldomains & BIT(clkwhich_sys2clk)) {
99 clkapidomains |= CTRL_CLK_DOMAIN_SYS2CLK;
100 }
101 if (clkhaldomains & BIT(clkwhich_hub2clk)) {
102 clkapidomains |= CTRL_CLK_DOMAIN_HUB2CLK;
103 }
104 if (clkhaldomains & BIT(clkwhich_pwrclk)) {
105 clkapidomains |= CTRL_CLK_DOMAIN_PWRCLK;
106 }
107 if (clkhaldomains & BIT(clkwhich_pciegenclk)) {
108 clkapidomains |= CTRL_CLK_DOMAIN_PCIEGENCLK;
109 }
110 if (clkhaldomains & BIT(clkwhich_mclk)) {
111 clkapidomains |= CTRL_CLK_DOMAIN_MCLK;
112 }
113 if (clkhaldomains & BIT(clkwhich_nvdclk)) {
114 clkapidomains |= CTRL_CLK_DOMAIN_NVDCLK;
115 }
116 if (clkhaldomains & BIT(clkwhich_dispclk)) {
117 clkapidomains |= CTRL_CLK_DOMAIN_DISPCLK;
118 }
119
120 return clkapidomains;
121}
122
123static int _clk_domains_pmudatainit_3x(struct gk20a *g,
124 struct boardobjgrp *pboardobjgrp,
125 struct nv_pmu_boardobjgrp_super *pboardobjgrppmu)
126{
127 struct nv_pmu_clk_clk_domain_boardobjgrp_set_header *pset =
128 (struct nv_pmu_clk_clk_domain_boardobjgrp_set_header *)
129 pboardobjgrppmu;
130 struct clk_domains *pdomains = (struct clk_domains *)pboardobjgrp;
131 int status = 0;
132
133 status = boardobjgrp_pmudatainit_e32(g, pboardobjgrp, pboardobjgrppmu);
134 if (status) {
135 nvgpu_err(g,
136 "error updating pmu boardobjgrp for clk domain 0x%x",
137 status);
138 goto done;
139 }
140
141 pset->vbios_domains = pdomains->vbios_domains;
142 pset->cntr_sampling_periodms = pdomains->cntr_sampling_periodms;
143 pset->version = CLK_DOMAIN_BOARDOBJGRP_VERSION;
144 pset->b_override_o_v_o_c = false;
145 pset->b_debug_mode = false;
146 pset->b_enforce_vf_monotonicity = pdomains->b_enforce_vf_monotonicity;
147 pset->b_enforce_vf_smoothening = pdomains->b_enforce_vf_smoothening;
148 if (g->ops.clk.split_rail_support) {
149 pset->volt_rails_max = 2;
150 } else {
151 pset->volt_rails_max = 1;
152 }
153 status = boardobjgrpmask_export(
154 &pdomains->master_domains_mask.super,
155 pdomains->master_domains_mask.super.bitcount,
156 &pset->master_domains_mask.super);
157
158 memcpy(&pset->deltas, &pdomains->deltas,
159 (sizeof(struct ctrl_clk_clk_delta)));
160
161done:
162 return status;
163}
164
165static int _clk_domains_pmudata_instget(struct gk20a *g,
166 struct nv_pmu_boardobjgrp *pmuboardobjgrp,
167 struct nv_pmu_boardobj **ppboardobjpmudata,
168 u8 idx)
169{
170 struct nv_pmu_clk_clk_domain_boardobj_grp_set *pgrp_set =
171 (struct nv_pmu_clk_clk_domain_boardobj_grp_set *)
172 pmuboardobjgrp;
173
174 nvgpu_log_info(g, " ");
175
176 /*check whether pmuboardobjgrp has a valid boardobj in index*/
177 if (((u32)BIT(idx) &
178 pgrp_set->hdr.data.super.obj_mask.super.data[0]) == 0) {
179 return -EINVAL;
180 }
181
182 *ppboardobjpmudata = (struct nv_pmu_boardobj *)
183 &pgrp_set->objects[idx].data.board_obj;
184 nvgpu_log_info(g, " Done");
185 return 0;
186}
187
188int clk_domain_sw_setup(struct gk20a *g)
189{
190 int status;
191 struct boardobjgrp *pboardobjgrp = NULL;
192 struct clk_domains *pclkdomainobjs;
193 struct clk_domain *pdomain;
194 struct clk_domain_3x_master *pdomain_master;
195 struct clk_domain_3x_slave *pdomain_slave;
196 u8 i;
197
198 nvgpu_log_info(g, " ");
199
200 status = boardobjgrpconstruct_e32(g, &g->clk_pmu.clk_domainobjs.super);
201 if (status) {
202 nvgpu_err(g,
203 "error creating boardobjgrp for clk domain, status - 0x%x",
204 status);
205 goto done;
206 }
207
208 pboardobjgrp = &g->clk_pmu.clk_domainobjs.super.super;
209 pclkdomainobjs = &(g->clk_pmu.clk_domainobjs);
210
211 BOARDOBJGRP_PMU_CONSTRUCT(pboardobjgrp, CLK, CLK_DOMAIN);
212
213 status = BOARDOBJGRP_PMU_CMD_GRP_SET_CONSTRUCT(g, pboardobjgrp,
214 clk, CLK, clk_domain, CLK_DOMAIN);
215 if (status) {
216 nvgpu_err(g,
217 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
218 status);
219 goto done;
220 }
221
222 pboardobjgrp->pmudatainit = _clk_domains_pmudatainit_3x;
223 pboardobjgrp->pmudatainstget = _clk_domains_pmudata_instget;
224
225 /* Initialize mask to zero.*/
226 boardobjgrpmask_e32_init(&pclkdomainobjs->prog_domains_mask, NULL);
227 boardobjgrpmask_e32_init(&pclkdomainobjs->master_domains_mask, NULL);
228 pclkdomainobjs->b_enforce_vf_monotonicity = true;
229 pclkdomainobjs->b_enforce_vf_smoothening = true;
230
231 memset(&pclkdomainobjs->ordered_noise_aware_list, 0,
232 sizeof(pclkdomainobjs->ordered_noise_aware_list));
233
234 memset(&pclkdomainobjs->ordered_noise_unaware_list, 0,
235 sizeof(pclkdomainobjs->ordered_noise_unaware_list));
236
237 memset(&pclkdomainobjs->deltas, 0,
238 sizeof(struct ctrl_clk_clk_delta));
239
240 status = devinit_get_clocks_table(g, pclkdomainobjs);
241 if (status) {
242 goto done;
243 }
244
245 BOARDOBJGRP_FOR_EACH(&(pclkdomainobjs->super.super),
246 struct clk_domain *, pdomain, i) {
247 pdomain_master = NULL;
248 if (pdomain->super.implements(g, &pdomain->super,
249 CTRL_CLK_CLK_DOMAIN_TYPE_3X_PROG)) {
250 status = boardobjgrpmask_bitset(
251 &pclkdomainobjs->prog_domains_mask.super, i);
252 if (status) {
253 goto done;
254 }
255 }
256
257 if (pdomain->super.implements(g, &pdomain->super,
258 CTRL_CLK_CLK_DOMAIN_TYPE_3X_MASTER)) {
259 status = boardobjgrpmask_bitset(
260 &pclkdomainobjs->master_domains_mask.super, i);
261 if (status) {
262 goto done;
263 }
264 }
265
266 if (pdomain->super.implements(g, &pdomain->super,
267 CTRL_CLK_CLK_DOMAIN_TYPE_3X_SLAVE)) {
268 pdomain_slave =
269 (struct clk_domain_3x_slave *)pdomain;
270 pdomain_master =
271 (struct clk_domain_3x_master *)
272 (CLK_CLK_DOMAIN_GET((&g->clk_pmu),
273 pdomain_slave->master_idx));
274 pdomain_master->slave_idxs_mask |= BIT(i);
275 }
276
277 }
278
279done:
280 nvgpu_log_info(g, " done status %x", status);
281 return status;
282}
283
284int clk_domain_pmu_setup(struct gk20a *g)
285{
286 int status;
287 struct boardobjgrp *pboardobjgrp = NULL;
288
289 nvgpu_log_info(g, " ");
290
291 pboardobjgrp = &g->clk_pmu.clk_domainobjs.super.super;
292
293 if (!pboardobjgrp->bconstructed) {
294 return -EINVAL;
295 }
296
297 status = pboardobjgrp->pmuinithandle(g, pboardobjgrp);
298
299 nvgpu_log_info(g, "Done");
300 return status;
301}
302
303static int devinit_get_clocks_table_35(struct gk20a *g,
304 struct clk_domains *pclkdomainobjs, u8 *clocks_table_ptr)
305{
306 int status = 0;
307 struct vbios_clocks_table_35_header clocks_table_header = { 0 };
308 struct vbios_clocks_table_35_entry clocks_table_entry = { 0 };
309 struct vbios_clocks_table_1x_hal_clock_entry *vbiosclktbl1xhalentry;
310 u8 *clocks_tbl_entry_ptr = NULL;
311 u32 index = 0;
312 struct clk_domain *pclkdomain_dev;
313 union {
314 struct boardobj boardobj;
315 struct clk_domain clk_domain;
316 struct clk_domain_3x v3x;
317 struct clk_domain_3x_fixed v3x_fixed;
318 struct clk_domain_35_prog v35_prog;
319 struct clk_domain_35_master v35_master;
320 struct clk_domain_35_slave v35_slave;
321 } clk_domain_data;
322
323 nvgpu_log_info(g, " ");
324
325 memcpy(&clocks_table_header, clocks_table_ptr,
326 VBIOS_CLOCKS_TABLE_35_HEADER_SIZE_09);
327 if (clocks_table_header.header_size <
328 (u8) VBIOS_CLOCKS_TABLE_35_HEADER_SIZE_09) {
329 status = -EINVAL;
330 goto done;
331 }
332
333 if (clocks_table_header.entry_size <
334 (u8) VBIOS_CLOCKS_TABLE_35_ENTRY_SIZE_11) {
335 status = -EINVAL;
336 goto done;
337 }
338
339 switch (clocks_table_header.clocks_hal) {
340 case CLK_TABLE_HAL_ENTRY_GP:
341 {
342 vbiosclktbl1xhalentry = vbiosclktbl1xhalentry_gp;
343 break;
344 }
345 case CLK_TABLE_HAL_ENTRY_GV:
346 {
347 vbiosclktbl1xhalentry = vbiosclktbl1xhalentry_gv;
348 break;
349 }
350 default:
351 {
352 status = -EINVAL;
353 goto done;
354 }
355 }
356
357 pclkdomainobjs->cntr_sampling_periodms =
358 (u16)clocks_table_header.cntr_sampling_periodms;
359
360 /* Read table entries*/
361 clocks_tbl_entry_ptr = clocks_table_ptr +
362 clocks_table_header.header_size;
363 for (index = 0; index < clocks_table_header.entry_count; index++) {
364 memcpy((void*) &clocks_table_entry, (void*) clocks_tbl_entry_ptr,
365 clocks_table_header.entry_size);
366 clk_domain_data.clk_domain.domain =
367 (u8) vbiosclktbl1xhalentry[index].domain;
368 clk_domain_data.clk_domain.api_domain =
369 clktranslatehalmumsettoapinumset(
370 (u32) BIT(clk_domain_data.clk_domain.domain));
371 clk_domain_data.v3x.b_noise_aware_capable =
372 vbiosclktbl1xhalentry[index].b_noise_aware_capable;
373
374 switch (BIOS_GET_FIELD(clocks_table_entry.flags0,
375 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_FLAGS0_USAGE)) {
376 case NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_FLAGS0_USAGE_FIXED:
377 {
378 clk_domain_data.boardobj.type =
379 CTRL_CLK_CLK_DOMAIN_TYPE_3X_FIXED;
380 clk_domain_data.v3x_fixed.freq_mhz = (u16)BIOS_GET_FIELD(
381 clocks_table_entry.param1,
382 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM1_FIXED_FREQUENCY_MHZ);
383 break;
384 }
385
386 case NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_FLAGS0_USAGE_MASTER:
387 {
388 clk_domain_data.boardobj.type =
389 CTRL_CLK_CLK_DOMAIN_TYPE_35_MASTER;
390 clk_domain_data.v35_prog.super.clk_prog_idx_first =
391 (u8)(BIOS_GET_FIELD(clocks_table_entry.param0,
392 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM0_PROG_CLK_PROG_IDX_FIRST));
393 clk_domain_data.v35_prog.super.clk_prog_idx_last =
394 (u8)(BIOS_GET_FIELD(clocks_table_entry.param0,
395 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM0_PROG_CLK_PROG_IDX_LAST));
396 clk_domain_data.v35_prog.super.noise_unaware_ordering_index =
397 (u8)(BIOS_GET_FIELD(clocks_table_entry.param2,
398 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM2_PROG_NOISE_UNAWARE_ORDERING_IDX));
399 if (clk_domain_data.v3x.b_noise_aware_capable) {
400 clk_domain_data.v35_prog.super.b_force_noise_unaware_ordering =
401 (bool)(BIOS_GET_FIELD(clocks_table_entry.param2,
402 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM2_PROG_FORCE_NOISE_UNAWARE_ORDERING));
403
404 } else {
405 clk_domain_data.v35_prog.super.noise_aware_ordering_index =
406 CTRL_CLK_CLK_DOMAIN_3X_PROG_ORDERING_INDEX_INVALID;
407 clk_domain_data.v35_prog.super.b_force_noise_unaware_ordering = false;
408 }
409 clk_domain_data.v35_prog.pre_volt_ordering_index =
410 (u8)(BIOS_GET_FIELD(clocks_table_entry.param2,
411 NV_VBIOS_CLOCKS_TABLE_35_ENTRY_PARAM2_PROG_PRE_VOLT_ORDERING_IDX));
412
413 clk_domain_data.v35_prog.post_volt_ordering_index =
414 (u8)(BIOS_GET_FIELD(clocks_table_entry.param2,
415 NV_VBIOS_CLOCKS_TABLE_35_ENTRY_PARAM2_PROG_POST_VOLT_ORDERING_IDX));
416
417 clk_domain_data.v35_prog.super.factory_delta.data.delta_khz = 0;
418 clk_domain_data.v35_prog.super.factory_delta.type = 0;
419
420 clk_domain_data.v35_prog.super.freq_delta_min_mhz =
421 (u16)(BIOS_GET_FIELD(clocks_table_entry.param1,
422 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM1_MASTER_FREQ_OC_DELTA_MIN_MHZ));
423
424 clk_domain_data.v35_prog.super.freq_delta_max_mhz =
425 (u16)(BIOS_GET_FIELD(clocks_table_entry.param1,
426 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM1_MASTER_FREQ_OC_DELTA_MAX_MHZ));
427 clk_domain_data.v35_prog.clk_vf_curve_count =
428 vbiosclktbl1xhalentry[index].clk_vf_curve_count;
429 break;
430 }
431
432 case NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_FLAGS0_USAGE_SLAVE:
433 {
434 clk_domain_data.boardobj.type =
435 CTRL_CLK_CLK_DOMAIN_TYPE_35_SLAVE;
436 clk_domain_data.v35_prog.super.clk_prog_idx_first =
437 (u8)(BIOS_GET_FIELD(clocks_table_entry.param0,
438 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM0_PROG_CLK_PROG_IDX_FIRST));
439 clk_domain_data.v35_prog.super.clk_prog_idx_last =
440 (u8)(BIOS_GET_FIELD(clocks_table_entry.param0,
441 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM0_PROG_CLK_PROG_IDX_LAST));
442 clk_domain_data.v35_prog.super.noise_unaware_ordering_index =
443 (u8)(BIOS_GET_FIELD(clocks_table_entry.param2,
444 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM2_PROG_NOISE_UNAWARE_ORDERING_IDX));
445
446 if (clk_domain_data.v3x.b_noise_aware_capable) {
447 clk_domain_data.v35_prog.super.b_force_noise_unaware_ordering =
448 (bool)(BIOS_GET_FIELD(clocks_table_entry.param2,
449 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM2_PROG_FORCE_NOISE_UNAWARE_ORDERING));
450
451 } else {
452 clk_domain_data.v35_prog.super.noise_aware_ordering_index =
453 CTRL_CLK_CLK_DOMAIN_3X_PROG_ORDERING_INDEX_INVALID;
454 clk_domain_data.v35_prog.super.b_force_noise_unaware_ordering = false;
455 }
456 clk_domain_data.v35_prog.pre_volt_ordering_index =
457 (u8)(BIOS_GET_FIELD(clocks_table_entry.param2,
458 NV_VBIOS_CLOCKS_TABLE_35_ENTRY_PARAM2_PROG_PRE_VOLT_ORDERING_IDX));
459
460 clk_domain_data.v35_prog.post_volt_ordering_index =
461 (u8)(BIOS_GET_FIELD(clocks_table_entry.param2,
462 NV_VBIOS_CLOCKS_TABLE_35_ENTRY_PARAM2_PROG_POST_VOLT_ORDERING_IDX));
463
464 clk_domain_data.v35_prog.super.factory_delta.data.delta_khz = 0;
465 clk_domain_data.v35_prog.super.factory_delta.type = 0;
466 clk_domain_data.v35_prog.super.freq_delta_min_mhz = 0;
467 clk_domain_data.v35_prog.super.freq_delta_max_mhz = 0;
468 clk_domain_data.v35_slave.slave.master_idx =
469 (u8)(BIOS_GET_FIELD(clocks_table_entry.param1,
470 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM1_SLAVE_MASTER_DOMAIN));
471 break;
472 }
473
474 default:
475 {
476 nvgpu_err(g,
477 "error reading clock domain entry %d", index);
478 status = -EINVAL;
479 goto done;
480 }
481
482 }
483 pclkdomain_dev = construct_clk_domain(g,
484 (void *)&clk_domain_data);
485 if (pclkdomain_dev == NULL) {
486 nvgpu_err(g,
487 "unable to construct clock domain boardobj for %d",
488 index);
489 status = -EINVAL;
490 goto done;
491 }
492 status = boardobjgrp_objinsert(
493 &pclkdomainobjs->super.super,
494 (struct boardobj *)(void*) pclkdomain_dev, index);
495 if (status != 0UL) {
496 nvgpu_err(g,
497 "unable to insert clock domain boardobj for %d", index);
498 status = (u32) -EINVAL;
499 goto done;
500 }
501 clocks_tbl_entry_ptr += clocks_table_header.entry_size;
502 }
503
504done:
505 nvgpu_log_info(g, " done status %x", status);
506 return status;
507}
508
509static int devinit_get_clocks_table_1x(struct gk20a *g,
510 struct clk_domains *pclkdomainobjs, u8 *clocks_table_ptr)
511{
512 int status = 0;
513 struct vbios_clocks_table_1x_header clocks_table_header = { 0 };
514 struct vbios_clocks_table_1x_entry clocks_table_entry = { 0 };
515 struct vbios_clocks_table_1x_hal_clock_entry *vbiosclktbl1xhalentry;
516 u8 *clocks_tbl_entry_ptr = NULL;
517 u32 index = 0;
518 struct clk_domain *pclkdomain_dev;
519 union {
520 struct boardobj boardobj;
521 struct clk_domain clk_domain;
522 struct clk_domain_3x v3x;
523 struct clk_domain_3x_fixed v3x_fixed;
524 struct clk_domain_3x_prog v3x_prog;
525 struct clk_domain_3x_master v3x_master;
526 struct clk_domain_3x_slave v3x_slave;
527 } clk_domain_data;
528
529 nvgpu_log_info(g, " ");
530
531 memcpy(&clocks_table_header, clocks_table_ptr,
532 VBIOS_CLOCKS_TABLE_1X_HEADER_SIZE_07);
533 if (clocks_table_header.header_size <
534 (u8) VBIOS_CLOCKS_TABLE_1X_HEADER_SIZE_07) {
535 status = -EINVAL;
536 goto done;
537 }
538
539 if (clocks_table_header.entry_size <
540 (u8) VBIOS_CLOCKS_TABLE_1X_ENTRY_SIZE_09) {
541 status = -EINVAL;
542 goto done;
543 }
544
545 switch (clocks_table_header.clocks_hal) {
546 case CLK_TABLE_HAL_ENTRY_GP:
547 {
548 vbiosclktbl1xhalentry = vbiosclktbl1xhalentry_gp;
549 break;
550 }
551 case CLK_TABLE_HAL_ENTRY_GV:
552 {
553 vbiosclktbl1xhalentry = vbiosclktbl1xhalentry_gv;
554 break;
555 }
556 default:
557 {
558 status = -EINVAL;
559 goto done;
560 }
561 }
562
563 pclkdomainobjs->cntr_sampling_periodms =
564 (u16)clocks_table_header.cntr_sampling_periodms;
565
566 /* Read table entries*/
567 clocks_tbl_entry_ptr = clocks_table_ptr +
568 VBIOS_CLOCKS_TABLE_1X_HEADER_SIZE_07;
569 for (index = 0; index < clocks_table_header.entry_count; index++) {
570 memcpy((void*) &clocks_table_entry, (void*) clocks_tbl_entry_ptr,
571 clocks_table_header.entry_size);
572 clk_domain_data.clk_domain.domain =
573 (u8) vbiosclktbl1xhalentry[index].domain;
574 clk_domain_data.clk_domain.api_domain =
575 clktranslatehalmumsettoapinumset(
576 BIT(clk_domain_data.clk_domain.domain));
577 clk_domain_data.v3x.b_noise_aware_capable =
578 vbiosclktbl1xhalentry[index].b_noise_aware_capable;
579
580 switch (BIOS_GET_FIELD(clocks_table_entry.flags0,
581 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_FLAGS0_USAGE)) {
582 case NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_FLAGS0_USAGE_FIXED:
583 {
584 clk_domain_data.boardobj.type =
585 CTRL_CLK_CLK_DOMAIN_TYPE_3X_FIXED;
586 clk_domain_data.v3x_fixed.freq_mhz = (u16)BIOS_GET_FIELD(
587 clocks_table_entry.param1,
588 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM1_FIXED_FREQUENCY_MHZ);
589 break;
590 }
591
592 case NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_FLAGS0_USAGE_MASTER:
593 {
594 clk_domain_data.boardobj.type =
595 CTRL_CLK_CLK_DOMAIN_TYPE_3X_MASTER;
596 clk_domain_data.v3x_prog.clk_prog_idx_first =
597 (u8)(BIOS_GET_FIELD(clocks_table_entry.param0,
598 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM0_PROG_CLK_PROG_IDX_FIRST));
599 clk_domain_data.v3x_prog.clk_prog_idx_last =
600 (u8)(BIOS_GET_FIELD(clocks_table_entry.param0,
601 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM0_PROG_CLK_PROG_IDX_LAST));
602 clk_domain_data.v3x_prog.noise_unaware_ordering_index =
603 (u8)(BIOS_GET_FIELD(clocks_table_entry.param2,
604 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM2_PROG_NOISE_UNAWARE_ORDERING_IDX));
605 if (clk_domain_data.v3x.b_noise_aware_capable) {
606 clk_domain_data.v3x_prog.noise_aware_ordering_index =
607 (u8)(BIOS_GET_FIELD(clocks_table_entry.param2,
608 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM2_PROG_NOISE_AWARE_ORDERING_IDX));
609 clk_domain_data.v3x_prog.b_force_noise_unaware_ordering =
610 (u8)(BIOS_GET_FIELD(clocks_table_entry.param2,
611 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM2_PROG_FORCE_NOISE_UNAWARE_ORDERING));
612 } else {
613 clk_domain_data.v3x_prog.noise_aware_ordering_index =
614 CTRL_CLK_CLK_DOMAIN_3X_PROG_ORDERING_INDEX_INVALID;
615 clk_domain_data.v3x_prog.b_force_noise_unaware_ordering = false;
616 }
617
618 clk_domain_data.v3x_prog.factory_delta.data.delta_khz = 0;
619 clk_domain_data.v3x_prog.factory_delta.type = 0;
620
621 clk_domain_data.v3x_prog.freq_delta_min_mhz =
622 (u16)(BIOS_GET_FIELD(clocks_table_entry.param1,
623 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM1_MASTER_FREQ_OC_DELTA_MIN_MHZ));
624
625 clk_domain_data.v3x_prog.freq_delta_max_mhz =
626 (u16)(BIOS_GET_FIELD(clocks_table_entry.param1,
627 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM1_MASTER_FREQ_OC_DELTA_MAX_MHZ));
628 break;
629 }
630
631 case NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_FLAGS0_USAGE_SLAVE:
632 {
633 clk_domain_data.boardobj.type =
634 CTRL_CLK_CLK_DOMAIN_TYPE_3X_SLAVE;
635 clk_domain_data.v3x_prog.clk_prog_idx_first =
636 (u8)(BIOS_GET_FIELD(clocks_table_entry.param0,
637 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM0_PROG_CLK_PROG_IDX_FIRST));
638 clk_domain_data.v3x_prog.clk_prog_idx_last =
639 (u8)(BIOS_GET_FIELD(clocks_table_entry.param0,
640 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM0_PROG_CLK_PROG_IDX_LAST));
641 clk_domain_data.v3x_prog.noise_unaware_ordering_index =
642 (u8)(BIOS_GET_FIELD(clocks_table_entry.param2,
643 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM2_PROG_NOISE_UNAWARE_ORDERING_IDX));
644
645 if (clk_domain_data.v3x.b_noise_aware_capable) {
646 clk_domain_data.v3x_prog.noise_aware_ordering_index =
647 (u8)(BIOS_GET_FIELD(clocks_table_entry.param2,
648 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM2_PROG_NOISE_AWARE_ORDERING_IDX));
649 clk_domain_data.v3x_prog.b_force_noise_unaware_ordering =
650 (u8)(BIOS_GET_FIELD(clocks_table_entry.param2,
651 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM2_PROG_FORCE_NOISE_UNAWARE_ORDERING));
652 } else {
653 clk_domain_data.v3x_prog.noise_aware_ordering_index =
654 CTRL_CLK_CLK_DOMAIN_3X_PROG_ORDERING_INDEX_INVALID;
655 clk_domain_data.v3x_prog.b_force_noise_unaware_ordering = false;
656 }
657 clk_domain_data.v3x_prog.factory_delta.data.delta_khz = 0;
658 clk_domain_data.v3x_prog.factory_delta.type = 0;
659 clk_domain_data.v3x_prog.freq_delta_min_mhz = 0;
660 clk_domain_data.v3x_prog.freq_delta_max_mhz = 0;
661 clk_domain_data.v3x_slave.master_idx =
662 (u8)(BIOS_GET_FIELD(clocks_table_entry.param1,
663 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM1_SLAVE_MASTER_DOMAIN));
664 break;
665 }
666
667 default:
668 {
669 nvgpu_err(g,
670 "error reading clock domain entry %d", index);
671 status = (u32) -EINVAL;
672 goto done;
673 }
674
675 }
676 pclkdomain_dev = construct_clk_domain(g,
677 (void *)&clk_domain_data);
678 if (pclkdomain_dev == NULL) {
679 nvgpu_err(g,
680 "unable to construct clock domain boardobj for %d",
681 index);
682 status = (u32) -EINVAL;
683 goto done;
684 }
685 status = boardobjgrp_objinsert(&pclkdomainobjs->super.super,
686 (struct boardobj *)(void *)pclkdomain_dev, index);
687 if (status != 0UL) {
688 nvgpu_err(g,
689 "unable to insert clock domain boardobj for %d", index);
690 status = (u32) -EINVAL;
691 goto done;
692 }
693 clocks_tbl_entry_ptr += clocks_table_header.entry_size;
694 }
695
696done:
697 nvgpu_log_info(g, " done status %x", status);
698 return status;
699}
700
701static int devinit_get_clocks_table(struct gk20a *g,
702 struct clk_domains *pclkdomainobjs)
703{
704 int status = 0;
705 u8 *clocks_table_ptr = NULL;
706 struct vbios_clocks_table_1x_header clocks_table_header = { 0 };
707 nvgpu_log_info(g, " ");
708
709 clocks_table_ptr = (u8 *)nvgpu_bios_get_perf_table_ptrs(g,
710 g->bios.clock_token, CLOCKS_TABLE);
711 if (clocks_table_ptr == NULL) {
712 status = -EINVAL;
713 goto done;
714 }
715 memcpy(&clocks_table_header, clocks_table_ptr,
716 VBIOS_CLOCKS_TABLE_1X_HEADER_SIZE_07);
717 if (clocks_table_header.version == 0x35U) {
718 devinit_get_clocks_table_35(g, pclkdomainobjs, clocks_table_ptr);
719 }
720 else {
721 devinit_get_clocks_table_1x(g, pclkdomainobjs, clocks_table_ptr);
722 }
723 done:
724 return status;
725
726}
727
728static int clkdomainclkproglink_not_supported(struct gk20a *g,
729 struct clk_pmupstate *pclk,
730 struct clk_domain *pdomain)
731{
732 nvgpu_log_info(g, " ");
733 return -EINVAL;
734}
735
736static int clkdomainvfsearch_stub(
737 struct gk20a *g,
738 struct clk_pmupstate *pclk,
739 struct clk_domain *pdomain,
740 u16 *clkmhz,
741 u32 *voltuv,
742 u8 rail)
743
744{
745 nvgpu_log_info(g, " ");
746 return -EINVAL;
747}
748
749static u32 clkdomaingetfpoints_stub(
750 struct gk20a *g,
751 struct clk_pmupstate *pclk,
752 struct clk_domain *pdomain,
753 u32 *pfpointscount,
754 u16 *pfreqpointsinmhz,
755 u8 rail)
756{
757 nvgpu_log_info(g, " ");
758 return -EINVAL;
759}
760
761
762static int clk_domain_construct_super(struct gk20a *g,
763 struct boardobj **ppboardobj,
764 u16 size, void *pargs)
765{
766 struct clk_domain *pdomain;
767 struct clk_domain *ptmpdomain = (struct clk_domain *)pargs;
768 int status = 0;
769
770 status = boardobj_construct_super(g, ppboardobj,
771 size, pargs);
772
773 if (status) {
774 return -EINVAL;
775 }
776
777 pdomain = (struct clk_domain *)*ppboardobj;
778
779 pdomain->super.pmudatainit =
780 clk_domain_pmudatainit_super;
781
782 pdomain->clkdomainclkproglink =
783 clkdomainclkproglink_not_supported;
784
785 pdomain->clkdomainclkvfsearch =
786 clkdomainvfsearch_stub;
787
788 pdomain->clkdomainclkgetfpoints =
789 clkdomaingetfpoints_stub;
790
791 pdomain->api_domain = ptmpdomain->api_domain;
792 pdomain->domain = ptmpdomain->domain;
793 pdomain->perf_domain_grp_idx =
794 ptmpdomain->perf_domain_grp_idx;
795
796 return status;
797}
798
799static int _clk_domain_pmudatainit_3x(struct gk20a *g,
800 struct boardobj *board_obj_ptr,
801 struct nv_pmu_boardobj *ppmudata)
802{
803 int status = 0;
804 struct clk_domain_3x *pclk_domain_3x;
805 struct nv_pmu_clk_clk_domain_3x_boardobj_set *pset;
806
807 nvgpu_log_info(g, " ");
808
809 status = clk_domain_pmudatainit_super(g, board_obj_ptr, ppmudata);
810 if (status != 0) {
811 return status;
812 }
813
814 pclk_domain_3x = (struct clk_domain_3x *)board_obj_ptr;
815
816 pset = (struct nv_pmu_clk_clk_domain_3x_boardobj_set *)ppmudata;
817
818 pset->b_noise_aware_capable = pclk_domain_3x->b_noise_aware_capable;
819
820 return status;
821}
822
823static int clk_domain_construct_3x(struct gk20a *g,
824 struct boardobj **ppboardobj,
825 u16 size, void *pargs)
826{
827 struct boardobj *ptmpobj = (struct boardobj *)pargs;
828 struct clk_domain_3x *pdomain;
829 struct clk_domain_3x *ptmpdomain =
830 (struct clk_domain_3x *)pargs;
831 int status = 0;
832
833 ptmpobj->type_mask = BIT(CTRL_CLK_CLK_DOMAIN_TYPE_3X);
834 status = clk_domain_construct_super(g, ppboardobj,
835 size, pargs);
836 if (status) {
837 return -EINVAL;
838 }
839
840 pdomain = (struct clk_domain_3x *)*ppboardobj;
841
842 pdomain->super.super.pmudatainit =
843 _clk_domain_pmudatainit_3x;
844
845 pdomain->b_noise_aware_capable = ptmpdomain->b_noise_aware_capable;
846
847 return status;
848}
849
850static int clkdomainclkproglink_3x_prog(struct gk20a *g,
851 struct clk_pmupstate *pclk,
852 struct clk_domain *pdomain)
853{
854 int status = 0;
855 struct clk_domain_3x_prog *p3xprog =
856 (struct clk_domain_3x_prog *)pdomain;
857 struct clk_prog *pprog = NULL;
858 u8 i;
859
860 nvgpu_log_info(g, " ");
861
862 for (i = p3xprog->clk_prog_idx_first;
863 i <= p3xprog->clk_prog_idx_last;
864 i++) {
865 pprog = CLK_CLK_PROG_GET(pclk, i);
866 if (pprog == NULL) {
867 status = -EINVAL;
868 }
869 }
870 return status;
871}
872
873static int clkdomaingetslaveclk(struct gk20a *g,
874 struct clk_pmupstate *pclk,
875 struct clk_domain *pdomain,
876 u16 *pclkmhz,
877 u16 masterclkmhz)
878{
879 int status = 0;
880 struct clk_prog *pprog = NULL;
881 struct clk_prog_1x_master *pprog1xmaster = NULL;
882 u8 slaveidx;
883 struct clk_domain_3x_master *p3xmaster;
884
885 nvgpu_log_info(g, " ");
886
887 if (pclkmhz == NULL) {
888 return -EINVAL;
889 }
890
891 if (masterclkmhz == 0) {
892 return -EINVAL;
893 }
894
895 slaveidx = BOARDOBJ_GET_IDX(pdomain);
896 p3xmaster = (struct clk_domain_3x_master *)
897 CLK_CLK_DOMAIN_GET(pclk,
898 ((struct clk_domain_3x_slave *)
899 pdomain)->master_idx);
900 pprog = CLK_CLK_PROG_GET(pclk, p3xmaster->super.clk_prog_idx_first);
901 pprog1xmaster = (struct clk_prog_1x_master *)pprog;
902
903 status = pprog1xmaster->getslaveclk(g, pclk, pprog1xmaster,
904 slaveidx, pclkmhz, masterclkmhz);
905 return status;
906}
907
908static int clkdomainvfsearch(struct gk20a *g,
909 struct clk_pmupstate *pclk,
910 struct clk_domain *pdomain,
911 u16 *pclkmhz,
912 u32 *pvoltuv,
913 u8 rail)
914{
915 int status = 0;
916 struct clk_domain_3x_master *p3xmaster =
917 (struct clk_domain_3x_master *)pdomain;
918 struct clk_prog *pprog = NULL;
919 struct clk_prog_1x_master *pprog1xmaster = NULL;
920 u8 i;
921 u8 *pslaveidx = NULL;
922 u8 slaveidx;
923 u16 clkmhz;
924 u32 voltuv;
925 u16 bestclkmhz;
926 u32 bestvoltuv;
927
928 nvgpu_log_info(g, " ");
929
930 if ((pclkmhz == NULL) || (pvoltuv == NULL)) {
931 return -EINVAL;
932 }
933
934 if ((*pclkmhz != 0) && (*pvoltuv != 0)) {
935 return -EINVAL;
936 }
937
938 bestclkmhz = *pclkmhz;
939 bestvoltuv = *pvoltuv;
940
941 if (pdomain->super.implements(g, &pdomain->super,
942 CTRL_CLK_CLK_DOMAIN_TYPE_3X_SLAVE)) {
943 slaveidx = BOARDOBJ_GET_IDX(pdomain);
944 pslaveidx = &slaveidx;
945 p3xmaster = (struct clk_domain_3x_master *)
946 CLK_CLK_DOMAIN_GET(pclk,
947 ((struct clk_domain_3x_slave *)
948 pdomain)->master_idx);
949 }
950 /* Iterate over the set of CLK_PROGs pointed at by this domain.*/
951 for (i = p3xmaster->super.clk_prog_idx_first;
952 i <= p3xmaster->super.clk_prog_idx_last;
953 i++) {
954 clkmhz = *pclkmhz;
955 voltuv = *pvoltuv;
956 pprog = CLK_CLK_PROG_GET(pclk, i);
957
958 /* MASTER CLK_DOMAINs must point to MASTER CLK_PROGs.*/
959 if (!pprog->super.implements(g, &pprog->super,
960 CTRL_CLK_CLK_PROG_TYPE_1X_MASTER)) {
961 status = -EINVAL;
962 goto done;
963 }
964
965 pprog1xmaster = (struct clk_prog_1x_master *)pprog;
966 status = pprog1xmaster->vflookup(g, pclk, pprog1xmaster,
967 pslaveidx, &clkmhz, &voltuv, rail);
968 /* if look up has found the V or F value matching to other
969 exit */
970 if (status == 0) {
971 if (*pclkmhz == 0) {
972 bestclkmhz = clkmhz;
973 } else {
974 bestvoltuv = voltuv;
975 break;
976 }
977 }
978 }
979 /* clk and volt sent as zero to print vf table */
980 if ((*pclkmhz == 0) && (*pvoltuv == 0)) {
981 status = 0;
982 goto done;
983 }
984 /* atleast one search found a matching value? */
985 if ((bestvoltuv != 0) && (bestclkmhz != 0)) {
986 *pclkmhz = bestclkmhz;
987 *pvoltuv = bestvoltuv;
988 status = 0;
989 goto done;
990 }
991done:
992 nvgpu_log_info(g, "done status %x", status);
993 return status;
994}
995
996static u32 clkdomaingetfpoints
997(
998 struct gk20a *g,
999 struct clk_pmupstate *pclk,
1000 struct clk_domain *pdomain,
1001 u32 *pfpointscount,
1002 u16 *pfreqpointsinmhz,
1003 u8 rail
1004)
1005{
1006 u32 status = 0;
1007 struct clk_domain_3x_master *p3xmaster =
1008 (struct clk_domain_3x_master *)pdomain;
1009 struct clk_prog *pprog = NULL;
1010 struct clk_prog_1x_master *pprog1xmaster = NULL;
1011 u32 fpointscount = 0;
1012 u32 remainingcount;
1013 u32 totalcount;
1014 u16 *freqpointsdata;
1015 u8 i;
1016
1017 nvgpu_log_info(g, " ");
1018
1019 if (pfpointscount == NULL) {
1020 return -EINVAL;
1021 }
1022
1023 if ((pfreqpointsinmhz == NULL) && (*pfpointscount != 0)) {
1024 return -EINVAL;
1025 }
1026
1027 if (pdomain->super.implements(g, &pdomain->super,
1028 CTRL_CLK_CLK_DOMAIN_TYPE_3X_SLAVE)) {
1029 return -EINVAL;
1030 }
1031
1032 freqpointsdata = pfreqpointsinmhz;
1033 totalcount = 0;
1034 fpointscount = *pfpointscount;
1035 remainingcount = fpointscount;
1036 /* Iterate over the set of CLK_PROGs pointed at by this domain.*/
1037 for (i = p3xmaster->super.clk_prog_idx_first;
1038 i <= p3xmaster->super.clk_prog_idx_last;
1039 i++) {
1040 pprog = CLK_CLK_PROG_GET(pclk, i);
1041 pprog1xmaster = (struct clk_prog_1x_master *)pprog;
1042 status = pprog1xmaster->getfpoints(g, pclk, pprog1xmaster,
1043 &fpointscount, &freqpointsdata, rail);
1044 if (status) {
1045 *pfpointscount = 0;
1046 goto done;
1047 }
1048 totalcount += fpointscount;
1049 if (*pfpointscount) {
1050 remainingcount -= fpointscount;
1051 fpointscount = remainingcount;
1052 } else {
1053 fpointscount = 0;
1054 }
1055
1056 }
1057
1058 *pfpointscount = totalcount;
1059done:
1060 nvgpu_log_info(g, "done status %x", status);
1061 return status;
1062}
1063
1064static int clk_domain_pmudatainit_35_prog(struct gk20a *g,
1065 struct boardobj *board_obj_ptr,
1066 struct nv_pmu_boardobj *ppmudata)
1067{
1068 int status = 0;
1069 struct clk_domain_35_prog *pclk_domain_35_prog;
1070 struct clk_domain_3x_prog *pclk_domain_3x_prog;
1071 struct nv_pmu_clk_clk_domain_35_prog_boardobj_set *pset;
1072 struct clk_domains *pdomains = &(g->clk_pmu.clk_domainobjs);
1073
1074 nvgpu_log_info(g, " ");
1075
1076 status = _clk_domain_pmudatainit_3x(g, board_obj_ptr, ppmudata);
1077 if (status != 0UL) {
1078 return status;
1079 }
1080
1081 pclk_domain_35_prog = (struct clk_domain_35_prog *)(void*)board_obj_ptr;
1082 pclk_domain_3x_prog = &pclk_domain_35_prog->super;
1083
1084 pset = (struct nv_pmu_clk_clk_domain_35_prog_boardobj_set *)
1085 (void*) ppmudata;
1086
1087 pset->super.clk_prog_idx_first = pclk_domain_3x_prog->clk_prog_idx_first;
1088 pset->super.clk_prog_idx_last = pclk_domain_3x_prog->clk_prog_idx_last;
1089 pset->super.b_force_noise_unaware_ordering =
1090 pclk_domain_3x_prog->b_force_noise_unaware_ordering;
1091 pset->super.factory_delta = pclk_domain_3x_prog->factory_delta;
1092 pset->super.freq_delta_min_mhz = pclk_domain_3x_prog->freq_delta_min_mhz;
1093 pset->super.freq_delta_max_mhz = pclk_domain_3x_prog->freq_delta_max_mhz;
1094 memcpy(&pset->super.deltas, &pdomains->deltas,
1095 (sizeof(struct ctrl_clk_clk_delta)));
1096 pset->pre_volt_ordering_index = pclk_domain_35_prog->pre_volt_ordering_index;
1097 pset->post_volt_ordering_index = pclk_domain_35_prog->post_volt_ordering_index;
1098 pset->clk_pos = pclk_domain_35_prog->clk_pos;
1099 pset->clk_vf_curve_count = pclk_domain_35_prog->clk_vf_curve_count;
1100
1101 return status;
1102}
1103
1104static int _clk_domain_pmudatainit_3x_prog(struct gk20a *g,
1105 struct boardobj *board_obj_ptr,
1106 struct nv_pmu_boardobj *ppmudata)
1107{
1108 int status = 0;
1109 struct clk_domain_3x_prog *pclk_domain_3x_prog;
1110 struct nv_pmu_clk_clk_domain_30_prog_boardobj_set *pset;
1111 struct clk_domains *pdomains = &(g->clk_pmu.clk_domainobjs);
1112
1113 nvgpu_log_info(g, " ");
1114
1115 status = _clk_domain_pmudatainit_3x(g, board_obj_ptr, ppmudata);
1116 if (status != 0) {
1117 return status;
1118 }
1119
1120 pclk_domain_3x_prog = (struct clk_domain_3x_prog *)board_obj_ptr;
1121
1122 pset = (struct nv_pmu_clk_clk_domain_30_prog_boardobj_set *)
1123 ppmudata;
1124
1125 pset->super.clk_prog_idx_first = pclk_domain_3x_prog->clk_prog_idx_first;
1126 pset->super.clk_prog_idx_last = pclk_domain_3x_prog->clk_prog_idx_last;
1127 pset->noise_unaware_ordering_index =
1128 pclk_domain_3x_prog->noise_unaware_ordering_index;
1129 pset->noise_aware_ordering_index =
1130 pclk_domain_3x_prog->noise_aware_ordering_index;
1131 pset->super.b_force_noise_unaware_ordering =
1132 pclk_domain_3x_prog->b_force_noise_unaware_ordering;
1133 pset->super.factory_delta = pclk_domain_3x_prog->factory_delta;
1134 pset->super.freq_delta_min_mhz = pclk_domain_3x_prog->freq_delta_min_mhz;
1135 pset->super.freq_delta_max_mhz = pclk_domain_3x_prog->freq_delta_max_mhz;
1136 memcpy(&pset->super.deltas, &pdomains->deltas,
1137 (sizeof(struct ctrl_clk_clk_delta)));
1138
1139 return status;
1140}
1141
1142static int clk_domain_construct_35_prog(struct gk20a *g,
1143 struct boardobj **ppboardobj,
1144 u16 size, void *pargs)
1145{
1146 struct boardobj *ptmpobj = (struct boardobj *)pargs;
1147 struct clk_domain_35_prog *pdomain;
1148 struct clk_domain_35_prog *ptmpdomain =
1149 (struct clk_domain_35_prog *)pargs;
1150 int status = 0;
1151
1152 ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_DOMAIN_TYPE_3X_PROG);
1153 status = clk_domain_construct_3x(g, ppboardobj, size, pargs);
1154 if (status != 0UL)
1155 {
1156 return (u32) -EINVAL;
1157 }
1158
1159 pdomain = (struct clk_domain_35_prog *)(void*) *ppboardobj;
1160
1161 pdomain->super.super.super.super.pmudatainit =
1162 clk_domain_pmudatainit_35_prog;
1163
1164 pdomain->super.super.super.clkdomainclkproglink =
1165 clkdomainclkproglink_3x_prog;
1166
1167 pdomain->super.super.super.clkdomainclkvfsearch =
1168 clkdomainvfsearch;
1169
1170 pdomain->super.super.super.clkdomainclkgetfpoints =
1171 clkdomaingetfpoints;
1172
1173 pdomain->super.clk_prog_idx_first = ptmpdomain->super.clk_prog_idx_first;
1174 pdomain->super.clk_prog_idx_last = ptmpdomain->super.clk_prog_idx_last;
1175 pdomain->super.noise_unaware_ordering_index =
1176 ptmpdomain->super.noise_unaware_ordering_index;
1177 pdomain->super.noise_aware_ordering_index =
1178 ptmpdomain->super.noise_aware_ordering_index;
1179 pdomain->super.b_force_noise_unaware_ordering =
1180 ptmpdomain->super.b_force_noise_unaware_ordering;
1181 pdomain->super.factory_delta = ptmpdomain->super.factory_delta;
1182 pdomain->super.freq_delta_min_mhz = ptmpdomain->super.freq_delta_min_mhz;
1183 pdomain->super.freq_delta_max_mhz = ptmpdomain->super.freq_delta_max_mhz;
1184 pdomain->pre_volt_ordering_index = ptmpdomain->pre_volt_ordering_index;
1185 pdomain->post_volt_ordering_index = ptmpdomain->post_volt_ordering_index;
1186 pdomain->clk_pos = ptmpdomain->clk_pos;
1187 pdomain->clk_vf_curve_count = ptmpdomain->clk_vf_curve_count;
1188
1189 return status;
1190}
1191
1192static int clk_domain_construct_3x_prog(struct gk20a *g,
1193 struct boardobj **ppboardobj,
1194 u16 size, void *pargs)
1195{
1196 struct boardobj *ptmpobj = (struct boardobj *)pargs;
1197 struct clk_domain_3x_prog *pdomain;
1198 struct clk_domain_3x_prog *ptmpdomain =
1199 (struct clk_domain_3x_prog *)pargs;
1200 int status = 0;
1201
1202 ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_DOMAIN_TYPE_3X_PROG);
1203 status = clk_domain_construct_3x(g, ppboardobj, size, pargs);
1204 if (status) {
1205 return -EINVAL;
1206 }
1207
1208 pdomain = (struct clk_domain_3x_prog *)*ppboardobj;
1209
1210 pdomain->super.super.super.pmudatainit =
1211 _clk_domain_pmudatainit_3x_prog;
1212
1213 pdomain->super.super.clkdomainclkproglink =
1214 clkdomainclkproglink_3x_prog;
1215
1216 pdomain->super.super.clkdomainclkvfsearch =
1217 clkdomainvfsearch;
1218
1219 pdomain->super.super.clkdomainclkgetfpoints =
1220 clkdomaingetfpoints;
1221
1222 pdomain->clk_prog_idx_first = ptmpdomain->clk_prog_idx_first;
1223 pdomain->clk_prog_idx_last = ptmpdomain->clk_prog_idx_last;
1224 pdomain->noise_unaware_ordering_index =
1225 ptmpdomain->noise_unaware_ordering_index;
1226 pdomain->noise_aware_ordering_index =
1227 ptmpdomain->noise_aware_ordering_index;
1228 pdomain->b_force_noise_unaware_ordering =
1229 ptmpdomain->b_force_noise_unaware_ordering;
1230 pdomain->factory_delta = ptmpdomain->factory_delta;
1231 pdomain->freq_delta_min_mhz = ptmpdomain->freq_delta_min_mhz;
1232 pdomain->freq_delta_max_mhz = ptmpdomain->freq_delta_max_mhz;
1233
1234 return status;
1235}
1236
1237static int _clk_domain_pmudatainit_35_slave(struct gk20a *g,
1238 struct boardobj *board_obj_ptr,
1239 struct nv_pmu_boardobj *ppmudata)
1240{
1241 int status = 0;
1242 struct clk_domain_35_slave *pclk_domain_35_slave;
1243 struct nv_pmu_clk_clk_domain_35_slave_boardobj_set *pset;
1244
1245 nvgpu_log_info(g, " ");
1246
1247 status = clk_domain_pmudatainit_35_prog(g, board_obj_ptr, ppmudata);
1248 if (status != 0UL) {
1249 return status;
1250 }
1251
1252 pclk_domain_35_slave = (struct clk_domain_35_slave *)(void*)board_obj_ptr;
1253
1254 pset = (struct nv_pmu_clk_clk_domain_35_slave_boardobj_set *)
1255 (void*) ppmudata;
1256
1257 pset->slave.master_idx = pclk_domain_35_slave->slave.master_idx;
1258
1259 return status;
1260}
1261
1262static int clk_domain_pmudatainit_3x_slave(struct gk20a *g,
1263 struct boardobj *board_obj_ptr,
1264 struct nv_pmu_boardobj *ppmudata)
1265{
1266 int status = 0;
1267 struct clk_domain_3x_slave *pclk_domain_3x_slave;
1268 struct nv_pmu_clk_clk_domain_3x_slave_boardobj_set *pset;
1269
1270 nvgpu_log_info(g, " ");
1271
1272 status = _clk_domain_pmudatainit_3x_prog(g, board_obj_ptr, ppmudata);
1273 if (status != 0) {
1274 return status;
1275 }
1276
1277 pclk_domain_3x_slave = (struct clk_domain_3x_slave *)board_obj_ptr;
1278
1279 pset = (struct nv_pmu_clk_clk_domain_3x_slave_boardobj_set *)
1280 ppmudata;
1281
1282 pset->master_idx = pclk_domain_3x_slave->master_idx;
1283
1284 return status;
1285}
1286
1287static int clk_domain_construct_35_slave(struct gk20a *g,
1288 struct boardobj **ppboardobj,
1289 u16 size, void *pargs)
1290{
1291 struct boardobj *ptmpobj = (struct boardobj *)pargs;
1292 struct clk_domain_35_slave *pdomain;
1293 struct clk_domain_35_slave *ptmpdomain =
1294 (struct clk_domain_35_slave *)pargs;
1295 int status = 0;
1296
1297 if (BOARDOBJ_GET_TYPE(pargs) != (u8) CTRL_CLK_CLK_DOMAIN_TYPE_35_SLAVE) {
1298 return (u32) -EINVAL;
1299 }
1300
1301 ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_DOMAIN_TYPE_35_SLAVE);
1302 status = clk_domain_construct_35_prog(g, ppboardobj, size, pargs);
1303 if (status != 0UL) {
1304 return (u32) -EINVAL;
1305 }
1306
1307 pdomain = (struct clk_domain_35_slave *)(void*)*ppboardobj;
1308
1309 pdomain->super.super.super.super.super.pmudatainit =
1310 _clk_domain_pmudatainit_35_slave;
1311
1312 pdomain->slave.master_idx = ptmpdomain->slave.master_idx;
1313
1314 pdomain->slave.clkdomainclkgetslaveclk =
1315 clkdomaingetslaveclk;
1316
1317 return status;
1318}
1319
1320static int clk_domain_construct_3x_slave(struct gk20a *g,
1321 struct boardobj **ppboardobj,
1322 u16 size, void *pargs)
1323{
1324 struct boardobj *ptmpobj = (struct boardobj *)pargs;
1325 struct clk_domain_3x_slave *pdomain;
1326 struct clk_domain_3x_slave *ptmpdomain =
1327 (struct clk_domain_3x_slave *)pargs;
1328 int status = 0;
1329
1330 if (BOARDOBJ_GET_TYPE(pargs) != (u8) CTRL_CLK_CLK_DOMAIN_TYPE_3X_SLAVE) {
1331 return -EINVAL;
1332 }
1333
1334 ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_DOMAIN_TYPE_3X_SLAVE);
1335 status = clk_domain_construct_3x_prog(g, ppboardobj, size, pargs);
1336 if (status != 0UL) {
1337 return -EINVAL;
1338 }
1339
1340 pdomain = (struct clk_domain_3x_slave *)*ppboardobj;
1341
1342 pdomain->super.super.super.super.pmudatainit =
1343 clk_domain_pmudatainit_3x_slave;
1344
1345 pdomain->master_idx = ptmpdomain->master_idx;
1346
1347 pdomain->clkdomainclkgetslaveclk =
1348 clkdomaingetslaveclk;
1349
1350 return status;
1351}
1352
1353static int clkdomainclkproglink_3x_master(struct gk20a *g,
1354 struct clk_pmupstate *pclk,
1355 struct clk_domain *pdomain)
1356{
1357 int status = 0;
1358 struct clk_domain_3x_master *p3xmaster =
1359 (struct clk_domain_3x_master *)pdomain;
1360 struct clk_prog *pprog = NULL;
1361 struct clk_prog_1x_master *pprog1xmaster = NULL;
1362 u16 freq_max_last_mhz = 0;
1363 u8 i;
1364
1365 nvgpu_log_info(g, " ");
1366
1367 status = clkdomainclkproglink_3x_prog(g, pclk, pdomain);
1368 if (status) {
1369 goto done;
1370 }
1371
1372 /* Iterate over the set of CLK_PROGs pointed at by this domain.*/
1373 for (i = p3xmaster->super.clk_prog_idx_first;
1374 i <= p3xmaster->super.clk_prog_idx_last;
1375 i++) {
1376 pprog = CLK_CLK_PROG_GET(pclk, i);
1377
1378 /* MASTER CLK_DOMAINs must point to MASTER CLK_PROGs.*/
1379 if (!pprog->super.implements(g, &pprog->super,
1380 CTRL_CLK_CLK_PROG_TYPE_1X_MASTER)) {
1381 status = -EINVAL;
1382 goto done;
1383 }
1384
1385 pprog1xmaster = (struct clk_prog_1x_master *)pprog;
1386 status = pprog1xmaster->vfflatten(g, pclk, pprog1xmaster,
1387 BOARDOBJ_GET_IDX(p3xmaster), &freq_max_last_mhz);
1388 if (status) {
1389 goto done;
1390 }
1391 }
1392done:
1393 nvgpu_log_info(g, "done status %x", status);
1394 return status;
1395}
1396
1397static int clk_domain_pmudatainit_35_master(struct gk20a *g,
1398 struct boardobj *board_obj_ptr,
1399 struct nv_pmu_boardobj *ppmudata)
1400{
1401 int status = 0;
1402 struct clk_domain_35_master *pclk_domain_35_master;
1403 struct nv_pmu_clk_clk_domain_35_master_boardobj_set *pset;
1404
1405 nvgpu_log_info(g, " ");
1406
1407 status = clk_domain_pmudatainit_35_prog(g, board_obj_ptr, ppmudata);
1408 if (status != 0UL) {
1409 return status;
1410 }
1411
1412 pclk_domain_35_master = (struct clk_domain_35_master *)
1413 (void*) board_obj_ptr;
1414
1415 pset = (struct nv_pmu_clk_clk_domain_35_master_boardobj_set *)
1416 (void*) ppmudata;
1417
1418 pset->master.slave_idxs_mask = pclk_domain_35_master->master.slave_idxs_mask;
1419
1420 return status;
1421}
1422
1423static int _clk_domain_pmudatainit_3x_master(struct gk20a *g,
1424 struct boardobj *board_obj_ptr,
1425 struct nv_pmu_boardobj *ppmudata)
1426{
1427 int status = 0;
1428 struct clk_domain_3x_master *pclk_domain_3x_master;
1429 struct nv_pmu_clk_clk_domain_3x_master_boardobj_set *pset;
1430
1431 nvgpu_log_info(g, " ");
1432
1433 status = _clk_domain_pmudatainit_3x_prog(g, board_obj_ptr, ppmudata);
1434 if (status != 0) {
1435 return status;
1436 }
1437
1438 pclk_domain_3x_master = (struct clk_domain_3x_master *)board_obj_ptr;
1439
1440 pset = (struct nv_pmu_clk_clk_domain_3x_master_boardobj_set *)
1441 ppmudata;
1442
1443 pset->slave_idxs_mask = pclk_domain_3x_master->slave_idxs_mask;
1444
1445 return status;
1446}
1447
1448static int clk_domain_construct_35_master(struct gk20a *g,
1449 struct boardobj **ppboardobj,
1450 u16 size, void *pargs)
1451{
1452 struct boardobj *ptmpobj = (struct boardobj *)pargs;
1453 struct clk_domain_35_master *pdomain;
1454 int status = 0;
1455
1456 if (BOARDOBJ_GET_TYPE(pargs) != (u8) CTRL_CLK_CLK_DOMAIN_TYPE_35_MASTER) {
1457 return -EINVAL;
1458 }
1459
1460 ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_DOMAIN_TYPE_35_MASTER);
1461 status = clk_domain_construct_35_prog(g, ppboardobj, size, pargs);
1462 if (status != 0UL) {
1463 return (u32) -EINVAL;
1464 }
1465
1466 pdomain = (struct clk_domain_35_master *)(void*) *ppboardobj;
1467
1468 pdomain->super.super.super.super.super.pmudatainit =
1469 clk_domain_pmudatainit_35_master;
1470 pdomain->super.super.super.super.clkdomainclkproglink =
1471 clkdomainclkproglink_3x_master;
1472
1473 pdomain->master.slave_idxs_mask = 0;
1474
1475 return status;
1476}
1477
1478static int clk_domain_construct_3x_master(struct gk20a *g,
1479 struct boardobj **ppboardobj,
1480 u16 size, void *pargs)
1481{
1482 struct boardobj *ptmpobj = (struct boardobj *)pargs;
1483 struct clk_domain_3x_master *pdomain;
1484 int status = 0;
1485
1486 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_CLK_CLK_DOMAIN_TYPE_3X_MASTER) {
1487 return -EINVAL;
1488 }
1489
1490 ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_DOMAIN_TYPE_3X_MASTER);
1491 status = clk_domain_construct_3x_prog(g, ppboardobj, size, pargs);
1492 if (status) {
1493 return -EINVAL;
1494 }
1495
1496 pdomain = (struct clk_domain_3x_master *)*ppboardobj;
1497
1498 pdomain->super.super.super.super.pmudatainit =
1499 _clk_domain_pmudatainit_3x_master;
1500 pdomain->super.super.super.clkdomainclkproglink =
1501 clkdomainclkproglink_3x_master;
1502
1503 pdomain->slave_idxs_mask = 0;
1504
1505 return status;
1506}
1507
1508static int clkdomainclkproglink_fixed(struct gk20a *g,
1509 struct clk_pmupstate *pclk,
1510 struct clk_domain *pdomain)
1511{
1512 nvgpu_log_info(g, " ");
1513 return 0;
1514}
1515
1516static int _clk_domain_pmudatainit_3x_fixed(struct gk20a *g,
1517 struct boardobj *board_obj_ptr,
1518 struct nv_pmu_boardobj *ppmudata)
1519{
1520 int status = 0;
1521 struct clk_domain_3x_fixed *pclk_domain_3x_fixed;
1522 struct nv_pmu_clk_clk_domain_3x_fixed_boardobj_set *pset;
1523
1524 nvgpu_log_info(g, " ");
1525
1526 status = _clk_domain_pmudatainit_3x(g, board_obj_ptr, ppmudata);
1527 if (status != 0) {
1528 return status;
1529 }
1530
1531 pclk_domain_3x_fixed = (struct clk_domain_3x_fixed *)board_obj_ptr;
1532
1533 pset = (struct nv_pmu_clk_clk_domain_3x_fixed_boardobj_set *)
1534 ppmudata;
1535
1536 pset->freq_mhz = pclk_domain_3x_fixed->freq_mhz;
1537
1538 return status;
1539}
1540
1541static int clk_domain_construct_3x_fixed(struct gk20a *g,
1542 struct boardobj **ppboardobj,
1543 u16 size, void *pargs)
1544{
1545 struct boardobj *ptmpobj = (struct boardobj *)pargs;
1546 struct clk_domain_3x_fixed *pdomain;
1547 struct clk_domain_3x_fixed *ptmpdomain =
1548 (struct clk_domain_3x_fixed *)pargs;
1549 int status = 0;
1550
1551 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_CLK_CLK_DOMAIN_TYPE_3X_FIXED) {
1552 return -EINVAL;
1553 }
1554
1555 ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_DOMAIN_TYPE_3X_FIXED);
1556 status = clk_domain_construct_3x(g, ppboardobj, size, pargs);
1557 if (status) {
1558 return -EINVAL;
1559 }
1560
1561 pdomain = (struct clk_domain_3x_fixed *)*ppboardobj;
1562
1563 pdomain->super.super.super.pmudatainit =
1564 _clk_domain_pmudatainit_3x_fixed;
1565
1566 pdomain->super.super.clkdomainclkproglink =
1567 clkdomainclkproglink_fixed;
1568
1569 pdomain->freq_mhz = ptmpdomain->freq_mhz;
1570
1571 return status;
1572}
1573
1574static struct clk_domain *construct_clk_domain(struct gk20a *g, void *pargs)
1575{
1576 struct boardobj *board_obj_ptr = NULL;
1577 u32 status;
1578
1579 nvgpu_log_info(g, " %d", BOARDOBJ_GET_TYPE(pargs));
1580 switch (BOARDOBJ_GET_TYPE(pargs)) {
1581 case CTRL_CLK_CLK_DOMAIN_TYPE_3X_FIXED:
1582 status = clk_domain_construct_3x_fixed(g, &board_obj_ptr,
1583 sizeof(struct clk_domain_3x_fixed), pargs);
1584 break;
1585
1586 case CTRL_CLK_CLK_DOMAIN_TYPE_35_MASTER:
1587 status = clk_domain_construct_35_master(g, &board_obj_ptr,
1588 sizeof(struct clk_domain_35_master), pargs);
1589 break;
1590
1591
1592 case CTRL_CLK_CLK_DOMAIN_TYPE_3X_MASTER:
1593 status = clk_domain_construct_3x_master(g, &board_obj_ptr,
1594 sizeof(struct clk_domain_3x_master), pargs);
1595 break;
1596
1597 case CTRL_CLK_CLK_DOMAIN_TYPE_35_SLAVE:
1598 status = clk_domain_construct_35_slave(g, &board_obj_ptr,
1599 sizeof(struct clk_domain_35_slave), pargs);
1600 break;
1601
1602 case CTRL_CLK_CLK_DOMAIN_TYPE_3X_SLAVE:
1603 status = clk_domain_construct_3x_slave(g, &board_obj_ptr,
1604 sizeof(struct clk_domain_3x_slave), pargs);
1605 break;
1606
1607 default:
1608 return NULL;
1609 }
1610
1611 if (status) {
1612 return NULL;
1613 }
1614
1615 nvgpu_log_info(g, " Done");
1616
1617 return (struct clk_domain *)board_obj_ptr;
1618}
1619
1620static int clk_domain_pmudatainit_super(struct gk20a *g,
1621 struct boardobj *board_obj_ptr,
1622 struct nv_pmu_boardobj *ppmudata)
1623{
1624 int status = 0;
1625 struct clk_domain *pclk_domain;
1626 struct nv_pmu_clk_clk_domain_boardobj_set *pset;
1627
1628 nvgpu_log_info(g, " ");
1629
1630 status = boardobj_pmudatainit_super(g, board_obj_ptr, ppmudata);
1631 if (status != 0) {
1632 return status;
1633 }
1634
1635 pclk_domain = (struct clk_domain *)board_obj_ptr;
1636
1637 pset = (struct nv_pmu_clk_clk_domain_boardobj_set *)ppmudata;
1638
1639 pset->domain = pclk_domain->domain;
1640 pset->api_domain = pclk_domain->api_domain;
1641 pset->perf_domain_grp_idx = pclk_domain->perf_domain_grp_idx;
1642
1643 return status;
1644}
1645
1646int clk_domain_clk_prog_link(struct gk20a *g, struct clk_pmupstate *pclk)
1647{
1648 int status = 0;
1649 struct clk_domain *pdomain;
1650 u8 i;
1651
1652 /* Iterate over all CLK_DOMAINs and flatten their VF curves.*/
1653 BOARDOBJGRP_FOR_EACH(&(pclk->clk_domainobjs.super.super),
1654 struct clk_domain *, pdomain, i) {
1655 status = pdomain->clkdomainclkproglink(g, pclk, pdomain);
1656 if (status) {
1657 nvgpu_err(g,
1658 "error flattening VF for CLK DOMAIN - 0x%x",
1659 pdomain->domain);
1660 goto done;
1661 }
1662 }
1663
1664done:
1665 return status;
1666}
diff --git a/include/clk/clk_domain.h b/include/clk/clk_domain.h
new file mode 100644
index 0000000..e5a7153
--- /dev/null
+++ b/include/clk/clk_domain.h
@@ -0,0 +1,157 @@
1/*
2* Copyright (c) 2016-2018, 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 NVGPU_CLK_DOMAIN_H
24#define NVGPU_CLK_DOMAIN_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
32#define CLK_DOMAIN_BOARDOBJGRP_VERSION 0x30
33#define CLK_TABLE_HAL_ENTRY_GP 0x02
34#define CLK_TABLE_HAL_ENTRY_GV 0x03
35
36struct clk_domains;
37struct clk_domain;
38enum nv_pmu_clk_clkwhich;
39
40/*data and function definition to talk to driver*/
41int clk_domain_sw_setup(struct gk20a *g);
42int clk_domain_pmu_setup(struct gk20a *g);
43
44typedef int clkproglink(struct gk20a *g, struct clk_pmupstate *pclk,
45 struct clk_domain *pdomain);
46
47typedef int clkvfsearch(struct gk20a *g, struct clk_pmupstate *pclk,
48 struct clk_domain *pdomain, u16 *clkmhz,
49 u32 *voltuv, u8 rail);
50
51typedef int clkgetslaveclk(struct gk20a *g, struct clk_pmupstate *pclk,
52 struct clk_domain *pdomain, u16 *clkmhz,
53 u16 masterclkmhz);
54
55typedef u32 clkgetfpoints(struct gk20a *g, struct clk_pmupstate *pclk,
56 struct clk_domain *pdomain, u32 *pfpointscount,
57 u16 *pfreqpointsinmhz, u8 rail);
58
59struct clk_domains {
60 struct boardobjgrp_e32 super;
61 u8 n_num_entries;
62 u8 version;
63 bool b_enforce_vf_monotonicity;
64 bool b_enforce_vf_smoothening;
65 bool b_override_o_v_o_c;
66 bool b_debug_mode;
67 u32 vbios_domains;
68 u16 cntr_sampling_periodms;
69 struct boardobjgrpmask_e32 prog_domains_mask;
70 struct boardobjgrpmask_e32 master_domains_mask;
71 struct ctrl_clk_clk_delta deltas;
72
73 struct clk_domain *ordered_noise_aware_list[CTRL_BOARDOBJ_MAX_BOARD_OBJECTS];
74
75 struct clk_domain *ordered_noise_unaware_list[CTRL_BOARDOBJ_MAX_BOARD_OBJECTS];
76};
77
78struct clk_domain {
79 struct boardobj super;
80 u32 api_domain;
81 u32 part_mask;
82 enum nv_pmu_clk_clkwhich domain;
83 u8 perf_domain_index;
84 u8 perf_domain_grp_idx;
85 u8 ratio_domain;
86 u8 usage;
87 clkproglink *clkdomainclkproglink;
88 clkvfsearch *clkdomainclkvfsearch;
89 clkgetfpoints *clkdomainclkgetfpoints;
90};
91
92struct clk_domain_3x {
93 struct clk_domain super;
94 bool b_noise_aware_capable;
95};
96
97struct clk_domain_3x_fixed {
98 struct clk_domain_3x super;
99 u16 freq_mhz;
100};
101
102struct clk_domain_3x_prog {
103 struct clk_domain_3x super;
104 u8 clk_prog_idx_first;
105 u8 clk_prog_idx_last;
106 bool b_force_noise_unaware_ordering;
107 struct ctrl_clk_freq_delta factory_delta;
108 short freq_delta_min_mhz;
109 short freq_delta_max_mhz;
110 struct ctrl_clk_clk_delta deltas;
111 u8 noise_unaware_ordering_index;
112 u8 noise_aware_ordering_index;
113};
114
115struct clk_domain_35_prog {
116 struct clk_domain_3x_prog super;
117 u8 pre_volt_ordering_index;
118 u8 post_volt_ordering_index;
119 u8 clk_pos;
120 u8 clk_vf_curve_count;
121};
122
123struct clk_domain_3x_master {
124 struct clk_domain_3x_prog super;
125 u32 slave_idxs_mask;
126};
127
128struct clk_domain_35_master {
129 struct clk_domain_35_prog super;
130 struct clk_domain_3x_master master;
131 struct boardobjgrpmask_e32 master_slave_domains_grp_mask;
132};
133
134struct clk_domain_3x_slave {
135 struct clk_domain_3x_prog super;
136 u8 master_idx;
137 clkgetslaveclk *clkdomainclkgetslaveclk;
138};
139
140struct clk_domain_30_slave {
141 u8 rsvd;
142 u8 master_idx;
143 clkgetslaveclk *clkdomainclkgetslaveclk;
144};
145
146struct clk_domain_35_slave {
147 struct clk_domain_35_prog super;
148 struct clk_domain_30_slave slave;
149};
150
151int clk_domain_clk_prog_link(struct gk20a *g, struct clk_pmupstate *pclk);
152
153#define CLK_CLK_DOMAIN_GET(pclk, idx) \
154 ((struct clk_domain *)BOARDOBJGRP_OBJ_GET_BY_IDX( \
155 &pclk->clk_domainobjs.super.super, (u8)(idx)))
156
157#endif /* NVGPU_CLK_DOMAIN_H */
diff --git a/include/clk/clk_fll.c b/include/clk/clk_fll.c
new file mode 100644
index 0000000..e67dd35
--- /dev/null
+++ b/include/clk/clk_fll.c
@@ -0,0 +1,495 @@
1/*
2 * Copyright (c) 2016-2018, 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/gk20a.h>
25
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 int devinit_get_fll_device_table(struct gk20a *g,
35 struct avfsfllobjs *pfllobjs);
36static struct fll_device *construct_fll_device(struct gk20a *g,
37 void *pargs);
38static int fll_device_init_pmudata_super(struct gk20a *g,
39 struct boardobj *board_obj_ptr,
40 struct nv_pmu_boardobj *ppmudata);
41
42static int _clk_fll_devgrp_pmudatainit_super(struct gk20a *g,
43 struct boardobjgrp *pboardobjgrp,
44 struct nv_pmu_boardobjgrp_super *pboardobjgrppmu)
45{
46 struct nv_pmu_clk_clk_fll_device_boardobjgrp_set_header *pset =
47 (struct nv_pmu_clk_clk_fll_device_boardobjgrp_set_header *)
48 pboardobjgrppmu;
49 struct avfsfllobjs *pfll_objs = (struct avfsfllobjs *)
50 pboardobjgrp;
51 int status = 0;
52
53 nvgpu_log_info(g, " ");
54
55 status = boardobjgrp_pmudatainit_e32(g, pboardobjgrp, pboardobjgrppmu);
56 if (status) {
57 nvgpu_err(g, "failed to init fll pmuobjgrp");
58 return status;
59 }
60 pset->lut_num_entries = pfll_objs->lut_num_entries;
61 pset->lut_step_size_uv = pfll_objs->lut_step_size_uv;
62 pset->lut_min_voltage_uv = pfll_objs->lut_min_voltage_uv;
63 pset->max_min_freq_mhz = pfll_objs->max_min_freq_mhz;
64
65 status = boardobjgrpmask_export(
66 &pfll_objs->lut_prog_master_mask.super,
67 pfll_objs->lut_prog_master_mask.super.bitcount,
68 &pset->lut_prog_master_mask.super);
69
70 nvgpu_log_info(g, " Done");
71 return status;
72}
73
74static int _clk_fll_devgrp_pmudata_instget(struct gk20a *g,
75 struct nv_pmu_boardobjgrp *pmuboardobjgrp,
76 struct nv_pmu_boardobj **ppboardobjpmudata,
77 u8 idx)
78{
79 struct nv_pmu_clk_clk_fll_device_boardobj_grp_set *pgrp_set =
80 (struct nv_pmu_clk_clk_fll_device_boardobj_grp_set *)
81 pmuboardobjgrp;
82
83 nvgpu_log_info(g, " ");
84
85 /*check whether pmuboardobjgrp has a valid boardobj in index*/
86 if (((u32)BIT(idx) &
87 pgrp_set->hdr.data.super.obj_mask.super.data[0]) == 0) {
88 return -EINVAL;
89 }
90
91 *ppboardobjpmudata = (struct nv_pmu_boardobj *)
92 &pgrp_set->objects[idx].data.board_obj;
93 nvgpu_log_info(g, " Done");
94 return 0;
95}
96
97static int _clk_fll_devgrp_pmustatus_instget(struct gk20a *g,
98 void *pboardobjgrppmu,
99 struct nv_pmu_boardobj_query **ppboardobjpmustatus,
100 u8 idx)
101{
102 struct nv_pmu_clk_clk_fll_device_boardobj_grp_get_status *pgrp_get_status =
103 (struct nv_pmu_clk_clk_fll_device_boardobj_grp_get_status *)
104 pboardobjgrppmu;
105
106 /*check whether pmuboardobjgrp has a valid boardobj in index*/
107 if (((u32)BIT(idx) &
108 pgrp_get_status->hdr.data.super.obj_mask.super.data[0]) == 0) {
109 return -EINVAL;
110 }
111
112 *ppboardobjpmustatus = (struct nv_pmu_boardobj_query *)
113 &pgrp_get_status->objects[idx].data.board_obj;
114 return 0;
115}
116
117int clk_fll_sw_setup(struct gk20a *g)
118{
119 int status;
120 struct boardobjgrp *pboardobjgrp = NULL;
121 struct avfsfllobjs *pfllobjs;
122 struct fll_device *pfll;
123 struct fll_device *pfll_master;
124 struct fll_device *pfll_local;
125 u8 i;
126 u8 j;
127
128 nvgpu_log_info(g, " ");
129
130 status = boardobjgrpconstruct_e32(g, &g->clk_pmu.avfs_fllobjs.super);
131 if (status) {
132 nvgpu_err(g,
133 "error creating boardobjgrp for fll, status - 0x%x", status);
134 goto done;
135 }
136 pfllobjs = &(g->clk_pmu.avfs_fllobjs);
137 pboardobjgrp = &(g->clk_pmu.avfs_fllobjs.super.super);
138
139 BOARDOBJGRP_PMU_CONSTRUCT(pboardobjgrp, CLK, FLL_DEVICE);
140
141 status = BOARDOBJGRP_PMU_CMD_GRP_SET_CONSTRUCT(g, pboardobjgrp,
142 clk, CLK, clk_fll_device, CLK_FLL_DEVICE);
143 if (status) {
144 nvgpu_err(g,
145 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
146 status);
147 goto done;
148 }
149
150 pboardobjgrp->pmudatainit = _clk_fll_devgrp_pmudatainit_super;
151 pboardobjgrp->pmudatainstget = _clk_fll_devgrp_pmudata_instget;
152 pboardobjgrp->pmustatusinstget = _clk_fll_devgrp_pmustatus_instget;
153 pfllobjs = (struct avfsfllobjs *)pboardobjgrp;
154 pfllobjs->lut_num_entries = g->ops.clk.lut_num_entries;
155 pfllobjs->lut_step_size_uv = CTRL_CLK_VIN_STEP_SIZE_UV;
156 pfllobjs->lut_min_voltage_uv = CTRL_CLK_LUT_MIN_VOLTAGE_UV;
157
158 /* Initialize lut prog master mask to zero.*/
159 boardobjgrpmask_e32_init(&pfllobjs->lut_prog_master_mask, NULL);
160
161 status = devinit_get_fll_device_table(g, pfllobjs);
162 if (status) {
163 goto done;
164 }
165
166 status = BOARDOBJGRP_PMU_CMD_GRP_GET_STATUS_CONSTRUCT(g,
167 &g->clk_pmu.avfs_fllobjs.super.super,
168 clk, CLK, clk_fll_device, CLK_FLL_DEVICE);
169 if (status) {
170 nvgpu_err(g,
171 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
172 status);
173 goto done;
174 }
175
176 BOARDOBJGRP_FOR_EACH(&(pfllobjs->super.super),
177 struct fll_device *, pfll, i) {
178 pfll_master = NULL;
179 j = 0;
180 BOARDOBJGRP_ITERATOR(&(pfllobjs->super.super),
181 struct fll_device *, pfll_local, j,
182 &pfllobjs->lut_prog_master_mask.super) {
183 if (pfll_local->clk_domain == pfll->clk_domain) {
184 pfll_master = pfll_local;
185 break;
186 }
187 }
188
189 if (pfll_master == NULL) {
190 status = boardobjgrpmask_bitset(
191 &pfllobjs->lut_prog_master_mask.super,
192 BOARDOBJ_GET_IDX(pfll));
193 if (status) {
194 nvgpu_err(g, "err setting lutprogmask");
195 goto done;
196 }
197 pfll_master = pfll;
198 }
199 status = pfll_master->lut_broadcast_slave_register(
200 g, pfllobjs, pfll_master, pfll);
201
202 if (status) {
203 nvgpu_err(g, "err setting lutslavemask");
204 goto done;
205 }
206 }
207done:
208 nvgpu_log_info(g, " done status %x", status);
209 return status;
210}
211
212int clk_fll_pmu_setup(struct gk20a *g)
213{
214 int status;
215 struct boardobjgrp *pboardobjgrp = NULL;
216
217 nvgpu_log_info(g, " ");
218
219 pboardobjgrp = &g->clk_pmu.avfs_fllobjs.super.super;
220
221 if (!pboardobjgrp->bconstructed) {
222 return -EINVAL;
223 }
224
225 status = pboardobjgrp->pmuinithandle(g, pboardobjgrp);
226
227 nvgpu_log_info(g, "Done");
228 return status;
229}
230
231static int devinit_get_fll_device_table(struct gk20a *g,
232 struct avfsfllobjs *pfllobjs)
233{
234 int status = 0;
235 u8 *fll_table_ptr = NULL;
236 struct fll_descriptor_header fll_desc_table_header_sz = { 0 };
237 struct fll_descriptor_header_10 fll_desc_table_header = { 0 };
238 struct fll_descriptor_entry_10 fll_desc_table_entry = { 0 };
239 u8 *fll_tbl_entry_ptr = NULL;
240 u32 index = 0;
241 struct fll_device fll_dev_data;
242 struct fll_device *pfll_dev;
243 struct vin_device *pvin_dev;
244 u32 desctablesize;
245 u32 vbios_domain = NV_PERF_DOMAIN_4X_CLOCK_DOMAIN_SKIP;
246 struct avfsvinobjs *pvinobjs = &g->clk_pmu.avfs_vinobjs;
247
248 nvgpu_log_info(g, " ");
249
250 fll_table_ptr = (u8 *)nvgpu_bios_get_perf_table_ptrs(g,
251 g->bios.clock_token, FLL_TABLE);
252 if (fll_table_ptr == NULL) {
253 status = -1;
254 goto done;
255 }
256
257 memcpy(&fll_desc_table_header_sz, fll_table_ptr,
258 sizeof(struct fll_descriptor_header));
259 if (fll_desc_table_header_sz.size >= FLL_DESCRIPTOR_HEADER_10_SIZE_6) {
260 desctablesize = FLL_DESCRIPTOR_HEADER_10_SIZE_6;
261 } else {
262 desctablesize = FLL_DESCRIPTOR_HEADER_10_SIZE_4;
263 }
264
265 memcpy(&fll_desc_table_header, fll_table_ptr, desctablesize);
266
267 if (desctablesize == FLL_DESCRIPTOR_HEADER_10_SIZE_6) {
268 pfllobjs->max_min_freq_mhz =
269 fll_desc_table_header.max_min_freq_mhz;
270 } else {
271 pfllobjs->max_min_freq_mhz = 0;
272 }
273
274 /* Read table entries*/
275 fll_tbl_entry_ptr = fll_table_ptr + desctablesize;
276 for (index = 0; index < fll_desc_table_header.entry_count; index++) {
277 u32 fll_id;
278
279 memcpy(&fll_desc_table_entry, fll_tbl_entry_ptr,
280 sizeof(struct fll_descriptor_entry_10));
281
282 if (fll_desc_table_entry.fll_device_type == CTRL_CLK_FLL_TYPE_DISABLED) {
283 continue;
284 }
285
286 fll_id = fll_desc_table_entry.fll_device_id;
287
288 if ( (u8)fll_desc_table_entry.vin_idx_logic != CTRL_CLK_VIN_ID_UNDEFINED) {
289 pvin_dev = CLK_GET_VIN_DEVICE(pvinobjs,
290 (u8)fll_desc_table_entry.vin_idx_logic);
291 if (pvin_dev == NULL) {
292 return -EINVAL;
293 } else {
294 pvin_dev->flls_shared_mask |= BIT(fll_id);
295 }
296 } else {
297 /* Return if Logic ADC device index is invalid*/
298 nvgpu_err(g, "Invalid Logic ADC specified for Nafll ID");
299 return -EINVAL;
300 }
301
302 fll_dev_data.lut_device.vselect_mode =
303 (u8)BIOS_GET_FIELD(fll_desc_table_entry.lut_params,
304 NV_FLL_DESC_LUT_PARAMS_VSELECT);
305
306 if ( (u8)fll_desc_table_entry.vin_idx_sram != CTRL_CLK_VIN_ID_UNDEFINED) {
307 pvin_dev = CLK_GET_VIN_DEVICE(pvinobjs,
308 (u8)fll_desc_table_entry.vin_idx_sram);
309 if (pvin_dev == NULL) {
310 return -EINVAL;
311 } else {
312 pvin_dev->flls_shared_mask |= BIT(fll_id);
313 }
314 } else {
315 /* Make sure VSELECT mode is set correctly to _LOGIC*/
316 if (fll_dev_data.lut_device.vselect_mode != CTRL_CLK_FLL_LUT_VSELECT_LOGIC) {
317 return -EINVAL;
318 }
319 }
320
321 fll_dev_data.super.type =
322 (u8)fll_desc_table_entry.fll_device_type;
323 fll_dev_data.id = (u8)fll_desc_table_entry.fll_device_id;
324 fll_dev_data.mdiv = (u8)BIOS_GET_FIELD(
325 fll_desc_table_entry.fll_params,
326 NV_FLL_DESC_FLL_PARAMS_MDIV);
327 fll_dev_data.input_freq_mhz =
328 (u16)fll_desc_table_entry.ref_freq_mhz;
329 fll_dev_data.min_freq_vfe_idx =
330 (u8)fll_desc_table_entry.min_freq_vfe_idx;
331 fll_dev_data.freq_ctrl_idx = CTRL_BOARDOBJ_IDX_INVALID;
332
333 vbios_domain = (u32)(fll_desc_table_entry.clk_domain &
334 NV_PERF_DOMAIN_4X_CLOCK_DOMAIN_MASK);
335 fll_dev_data.clk_domain =
336 g->ops.pmu_ver.clk.get_vbios_clk_domain(vbios_domain);
337
338 fll_dev_data.rail_idx_for_lut = 0;
339 fll_dev_data.vin_idx_logic =
340 (u8)fll_desc_table_entry.vin_idx_logic;
341 fll_dev_data.vin_idx_sram =
342 (u8)fll_desc_table_entry.vin_idx_sram;
343 fll_dev_data.b_skip_pldiv_below_dvco_min =
344 (bool)BIOS_GET_FIELD(fll_desc_table_entry.fll_params,
345 NV_FLL_DESC_FLL_PARAMS_SKIP_PLDIV_BELOW_DVCO_MIN);
346 fll_dev_data.lut_device.hysteresis_threshold =
347 (u8)BIOS_GET_FIELD(fll_desc_table_entry.lut_params,
348 NV_FLL_DESC_LUT_PARAMS_HYSTERISIS_THRESHOLD);
349 fll_dev_data.regime_desc.regime_id =
350 CTRL_CLK_FLL_REGIME_ID_FFR;
351 fll_dev_data.regime_desc.fixed_freq_regime_limit_mhz =
352 (u16)fll_desc_table_entry.ffr_cutoff_freq_mhz;
353 fll_dev_data.regime_desc.target_regime_id_override=0;
354
355 /*construct fll device*/
356 pfll_dev = construct_fll_device(g, (void *)&fll_dev_data);
357
358 status = boardobjgrp_objinsert(&pfllobjs->super.super,
359 (struct boardobj *)pfll_dev, index);
360 fll_tbl_entry_ptr += fll_desc_table_header.entry_size;
361 }
362
363done:
364 nvgpu_log_info(g, " done status %x", status);
365 return status;
366}
367
368u32 nvgpu_clk_get_vbios_clk_domain_gv10x( u32 vbios_domain)
369{
370 if (vbios_domain == 0) {
371 return CTRL_CLK_DOMAIN_GPCCLK;
372 } else if (vbios_domain == 1) {
373 return CTRL_CLK_DOMAIN_XBARCLK;
374 } else if (vbios_domain == 3) {
375 return CTRL_CLK_DOMAIN_SYSCLK;
376 } else if (vbios_domain == 5) {
377 return CTRL_CLK_DOMAIN_NVDCLK;
378 }
379 return 0;
380}
381
382u32 nvgpu_clk_get_vbios_clk_domain_gp10x( u32 vbios_domain)
383{
384 if (vbios_domain == 0) {
385 return CTRL_CLK_DOMAIN_GPC2CLK;
386 } else if (vbios_domain == 1) {
387 return CTRL_CLK_DOMAIN_XBAR2CLK;
388 } else if (vbios_domain == 3) {
389 return CTRL_CLK_DOMAIN_SYS2CLK;
390 }
391 return 0;
392}
393
394static u32 lutbroadcastslaveregister(struct gk20a *g,
395 struct avfsfllobjs *pfllobjs,
396 struct fll_device *pfll,
397 struct fll_device *pfll_slave)
398{
399 if (pfll->clk_domain != pfll_slave->clk_domain) {
400 return -EINVAL;
401 }
402
403 return boardobjgrpmask_bitset(&pfll->
404 lut_prog_broadcast_slave_mask.super,
405 BOARDOBJ_GET_IDX(pfll_slave));
406}
407
408static struct fll_device *construct_fll_device(struct gk20a *g,
409 void *pargs)
410{
411 struct boardobj *board_obj_ptr = NULL;
412 struct fll_device *pfll_dev;
413 struct fll_device *board_obj_fll_ptr = NULL;
414 int status;
415
416 nvgpu_log_info(g, " ");
417 status = boardobj_construct_super(g, &board_obj_ptr,
418 sizeof(struct fll_device), pargs);
419 if (status) {
420 return NULL;
421 }
422
423 pfll_dev = (struct fll_device *)pargs;
424 board_obj_fll_ptr = (struct fll_device *)board_obj_ptr;
425 board_obj_ptr->pmudatainit = fll_device_init_pmudata_super;
426 board_obj_fll_ptr->lut_broadcast_slave_register =
427 lutbroadcastslaveregister;
428 board_obj_fll_ptr->id = pfll_dev->id;
429 board_obj_fll_ptr->mdiv = pfll_dev->mdiv;
430 board_obj_fll_ptr->rail_idx_for_lut = pfll_dev->rail_idx_for_lut;
431 board_obj_fll_ptr->input_freq_mhz = pfll_dev->input_freq_mhz;
432 board_obj_fll_ptr->clk_domain = pfll_dev->clk_domain;
433 board_obj_fll_ptr->vin_idx_logic = pfll_dev->vin_idx_logic;
434 board_obj_fll_ptr->vin_idx_sram = pfll_dev->vin_idx_sram;
435 board_obj_fll_ptr->min_freq_vfe_idx =
436 pfll_dev->min_freq_vfe_idx;
437 board_obj_fll_ptr->freq_ctrl_idx = pfll_dev->freq_ctrl_idx;
438 board_obj_fll_ptr->b_skip_pldiv_below_dvco_min =
439 pfll_dev->b_skip_pldiv_below_dvco_min;
440 memcpy(&board_obj_fll_ptr->lut_device, &pfll_dev->lut_device,
441 sizeof(struct nv_pmu_clk_lut_device_desc));
442 memcpy(&board_obj_fll_ptr->regime_desc, &pfll_dev->regime_desc,
443 sizeof(struct nv_pmu_clk_regime_desc));
444 boardobjgrpmask_e32_init(
445 &board_obj_fll_ptr->lut_prog_broadcast_slave_mask, NULL);
446
447 nvgpu_log_info(g, " Done");
448
449 return (struct fll_device *)board_obj_ptr;
450}
451
452static int fll_device_init_pmudata_super(struct gk20a *g,
453 struct boardobj *board_obj_ptr,
454 struct nv_pmu_boardobj *ppmudata)
455{
456 int status = 0;
457 struct fll_device *pfll_dev;
458 struct nv_pmu_clk_clk_fll_device_boardobj_set *perf_pmu_data;
459
460 nvgpu_log_info(g, " ");
461
462 status = boardobj_pmudatainit_super(g, board_obj_ptr, ppmudata);
463 if (status != 0) {
464 return status;
465 }
466
467 pfll_dev = (struct fll_device *)board_obj_ptr;
468 perf_pmu_data = (struct nv_pmu_clk_clk_fll_device_boardobj_set *)
469 ppmudata;
470
471 perf_pmu_data->id = pfll_dev->id;
472 perf_pmu_data->mdiv = pfll_dev->mdiv;
473 perf_pmu_data->rail_idx_for_lut = pfll_dev->rail_idx_for_lut;
474 perf_pmu_data->input_freq_mhz = pfll_dev->input_freq_mhz;
475 perf_pmu_data->vin_idx_logic = pfll_dev->vin_idx_logic;
476 perf_pmu_data->vin_idx_sram = pfll_dev->vin_idx_sram;
477 perf_pmu_data->clk_domain = pfll_dev->clk_domain;
478 perf_pmu_data->min_freq_vfe_idx =
479 pfll_dev->min_freq_vfe_idx;
480 perf_pmu_data->freq_ctrl_idx = pfll_dev->freq_ctrl_idx;
481 perf_pmu_data->b_skip_pldiv_below_dvco_min = pfll_dev->b_skip_pldiv_below_dvco_min;
482 memcpy(&perf_pmu_data->lut_device, &pfll_dev->lut_device,
483 sizeof(struct nv_pmu_clk_lut_device_desc));
484 memcpy(&perf_pmu_data->regime_desc, &pfll_dev->regime_desc,
485 sizeof(struct nv_pmu_clk_regime_desc));
486
487 status = boardobjgrpmask_export(
488 &pfll_dev->lut_prog_broadcast_slave_mask.super,
489 pfll_dev->lut_prog_broadcast_slave_mask.super.bitcount,
490 &perf_pmu_data->lut_prog_broadcast_slave_mask.super);
491
492 nvgpu_log_info(g, " Done");
493
494 return status;
495}
diff --git a/include/clk/clk_fll.h b/include/clk/clk_fll.h
new file mode 100644
index 0000000..6cbdfe2
--- /dev/null
+++ b/include/clk/clk_fll.h
@@ -0,0 +1,81 @@
1/*
2* Copyright (c) 2016-2018, 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 NVGPU_CLK_FLL_H
24#define NVGPU_CLK_FLL_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*/
31int clk_fll_sw_setup(struct gk20a *g);
32int 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 bool b_skip_pldiv_below_dvco_min;
65 bool b_dvco_1x;
66 struct boardobjgrpmask_e32 lut_prog_broadcast_slave_mask;
67 fll_lut_broadcast_slave_register *lut_broadcast_slave_register;
68};
69
70u32 nvgpu_clk_get_vbios_clk_domain_gv10x( u32 vbios_domain);
71u32 nvgpu_clk_get_vbios_clk_domain_gp10x( u32 vbios_domain);
72
73#define CLK_FLL_LUT_VF_NUM_ENTRIES(pclk) \
74 (pclk->avfs_fllobjs.lut_num_entries)
75
76#define CLK_FLL_LUT_MIN_VOLTAGE_UV(pclk) \
77 (pclk->avfs_fllobjs.lut_min_voltage_uv)
78#define CLK_FLL_LUT_STEP_SIZE_UV(pclk) \
79 (pclk->avfs_fllobjs.lut_step_size_uv)
80
81#endif /* NVGPU_CLK_FLL_H */
diff --git a/include/clk/clk_freq_controller.c b/include/clk/clk_freq_controller.c
new file mode 100644
index 0000000..f4d09b0
--- /dev/null
+++ b/include/clk/clk_freq_controller.c
@@ -0,0 +1,462 @@
1/*
2 * Copyright (c) 2016-2018, 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/gk20a.h>
25
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 int 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 int status = 0;
42
43 status = boardobj_pmudatainit_super(g, board_obj_ptr, ppmudata);
44 if (status) {
45 return status;
46 }
47
48 pfreq_cntlr_set =
49 (struct nv_pmu_clk_clk_freq_controller_boardobj_set *)ppmudata;
50 pfreq_cntlr = (struct clk_freq_controller *)board_obj_ptr;
51
52 pfreq_cntlr_set->controller_id = pfreq_cntlr->controller_id;
53 pfreq_cntlr_set->clk_domain = pfreq_cntlr->clk_domain;
54 pfreq_cntlr_set->parts_freq_mode = pfreq_cntlr->parts_freq_mode;
55 pfreq_cntlr_set->bdisable = pfreq_cntlr->bdisable;
56 pfreq_cntlr_set->freq_cap_noise_unaware_vmin_above =
57 pfreq_cntlr->freq_cap_noise_unaware_vmin_above;
58 pfreq_cntlr_set->freq_cap_noise_unaware_vmin_below =
59 pfreq_cntlr->freq_cap_noise_unaware_vmin_below;
60 pfreq_cntlr_set->freq_hyst_pos_mhz = pfreq_cntlr->freq_hyst_pos_mhz;
61 pfreq_cntlr_set->freq_hyst_neg_mhz = pfreq_cntlr->freq_hyst_neg_mhz;
62
63 return status;
64}
65
66static int clk_freq_controller_pmudatainit_pi(struct gk20a *g,
67 struct boardobj *board_obj_ptr,
68 struct nv_pmu_boardobj *ppmudata)
69{
70 struct nv_pmu_clk_clk_freq_controller_pi_boardobj_set
71 *pfreq_cntlr_pi_set;
72 struct clk_freq_controller_pi *pfreq_cntlr_pi;
73 int status = 0;
74
75 status = clk_freq_controller_pmudatainit_super(g,
76 board_obj_ptr, ppmudata);
77 if (status) {
78 return -1;
79 }
80
81 pfreq_cntlr_pi_set =
82 (struct nv_pmu_clk_clk_freq_controller_pi_boardobj_set *)
83 ppmudata;
84 pfreq_cntlr_pi = (struct clk_freq_controller_pi *)board_obj_ptr;
85
86 pfreq_cntlr_pi_set->prop_gain = pfreq_cntlr_pi->prop_gain;
87 pfreq_cntlr_pi_set->integ_gain = pfreq_cntlr_pi->integ_gain;
88 pfreq_cntlr_pi_set->integ_decay = pfreq_cntlr_pi->integ_decay;
89 pfreq_cntlr_pi_set->volt_delta_min = pfreq_cntlr_pi->volt_delta_min;
90 pfreq_cntlr_pi_set->volt_delta_max = pfreq_cntlr_pi->volt_delta_max;
91 pfreq_cntlr_pi_set->slowdown_pct_min = pfreq_cntlr_pi->slowdown_pct_min;
92 pfreq_cntlr_pi_set->bpoison = pfreq_cntlr_pi->bpoison;
93
94 return status;
95}
96
97static int clk_freq_controller_construct_super(struct gk20a *g,
98 struct boardobj **ppboardobj,
99 u16 size, void *pargs)
100{
101 struct clk_freq_controller *pfreq_cntlr = NULL;
102 struct clk_freq_controller *pfreq_cntlr_tmp = NULL;
103 int status = 0;
104
105 status = boardobj_construct_super(g, ppboardobj, size, pargs);
106 if (status) {
107 return -EINVAL;
108 }
109
110 pfreq_cntlr_tmp = (struct clk_freq_controller *)pargs;
111 pfreq_cntlr = (struct clk_freq_controller *)*ppboardobj;
112
113 pfreq_cntlr->super.pmudatainit = clk_freq_controller_pmudatainit_super;
114
115 pfreq_cntlr->controller_id = pfreq_cntlr_tmp->controller_id;
116 pfreq_cntlr->clk_domain = pfreq_cntlr_tmp->clk_domain;
117 pfreq_cntlr->parts_freq_mode = pfreq_cntlr_tmp->parts_freq_mode;
118 pfreq_cntlr->freq_cap_noise_unaware_vmin_above =
119 pfreq_cntlr_tmp->freq_cap_noise_unaware_vmin_above;
120 pfreq_cntlr->freq_cap_noise_unaware_vmin_below =
121 pfreq_cntlr_tmp->freq_cap_noise_unaware_vmin_below;
122 pfreq_cntlr->freq_hyst_pos_mhz = pfreq_cntlr_tmp->freq_hyst_pos_mhz;
123 pfreq_cntlr->freq_hyst_neg_mhz = pfreq_cntlr_tmp->freq_hyst_neg_mhz;
124
125 return status;
126}
127
128static int clk_freq_controller_construct_pi(struct gk20a *g,
129 struct boardobj **ppboardobj,
130 u16 size, void *pargs)
131{
132 struct clk_freq_controller_pi *pfreq_cntlr_pi = NULL;
133 struct clk_freq_controller_pi *pfreq_cntlr_pi_tmp = NULL;
134 int status = 0;
135
136 status = clk_freq_controller_construct_super(g, ppboardobj,
137 size, pargs);
138 if (status) {
139 return -EINVAL;
140 }
141
142 pfreq_cntlr_pi = (struct clk_freq_controller_pi *)*ppboardobj;
143 pfreq_cntlr_pi_tmp = (struct clk_freq_controller_pi *)pargs;
144
145 pfreq_cntlr_pi->super.super.pmudatainit =
146 clk_freq_controller_pmudatainit_pi;
147
148 pfreq_cntlr_pi->prop_gain = pfreq_cntlr_pi_tmp->prop_gain;
149 pfreq_cntlr_pi->integ_gain = pfreq_cntlr_pi_tmp->integ_gain;
150 pfreq_cntlr_pi->integ_decay = pfreq_cntlr_pi_tmp->integ_decay;
151 pfreq_cntlr_pi->volt_delta_min = pfreq_cntlr_pi_tmp->volt_delta_min;
152 pfreq_cntlr_pi->volt_delta_max = pfreq_cntlr_pi_tmp->volt_delta_max;
153 pfreq_cntlr_pi->slowdown_pct_min = pfreq_cntlr_pi_tmp->slowdown_pct_min;
154 pfreq_cntlr_pi->bpoison = pfreq_cntlr_pi_tmp->bpoison;
155
156 return status;
157}
158
159static struct clk_freq_controller *clk_clk_freq_controller_construct(
160 struct gk20a *g,
161 void *pargs)
162{
163 struct boardobj *board_obj_ptr = NULL;
164 int status = 0;
165
166 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_CLK_CLK_FREQ_CONTROLLER_TYPE_PI) {
167 return NULL;
168 }
169
170 status = clk_freq_controller_construct_pi(g, &board_obj_ptr,
171 sizeof(struct clk_freq_controller_pi), pargs);
172 if (status) {
173 return NULL;
174 }
175
176 return (struct clk_freq_controller *)board_obj_ptr;
177}
178
179
180static int clk_get_freq_controller_table(struct gk20a *g,
181 struct clk_freq_controllers *pclk_freq_controllers)
182{
183 int status = 0;
184 u8 *pfreq_controller_table_ptr = NULL;
185 struct vbios_fct_1x_header header = { 0 };
186 struct vbios_fct_1x_entry entry = { 0 };
187 u8 entry_idx;
188 u8 *entry_offset;
189 struct clk_freq_controller *pclk_freq_cntr = NULL;
190 struct clk_freq_controller *ptmp_freq_cntr = NULL;
191 struct clk_freq_controller_pi *ptmp_freq_cntr_pi = NULL;
192 struct clk_domain *pclk_domain;
193
194 struct freq_controller_data_type {
195 union {
196 struct boardobj board_obj;
197 struct clk_freq_controller freq_controller;
198 struct clk_freq_controller_pi freq_controller_pi;
199 };
200 } freq_controller_data;
201
202 pfreq_controller_table_ptr =
203 (u8 *)nvgpu_bios_get_perf_table_ptrs(g,
204 g->bios.clock_token,
205 FREQUENCY_CONTROLLER_TABLE);
206 if (pfreq_controller_table_ptr == NULL) {
207 status = -EINVAL;
208 goto done;
209 }
210
211 memcpy(&header, pfreq_controller_table_ptr,
212 sizeof(struct vbios_fct_1x_header));
213
214 pclk_freq_controllers->sampling_period_ms = header.sampling_period_ms;
215 pclk_freq_controllers->volt_policy_idx = 0;
216
217 /* Read in the entries. */
218 for (entry_idx = 0; entry_idx < header.entry_count; entry_idx++) {
219 entry_offset = (pfreq_controller_table_ptr +
220 header.header_size + (entry_idx * header.entry_size));
221
222 memset(&freq_controller_data, 0x0,
223 sizeof(struct freq_controller_data_type));
224 ptmp_freq_cntr = &freq_controller_data.freq_controller;
225 ptmp_freq_cntr_pi = &freq_controller_data.freq_controller_pi;
226
227 memcpy(&entry, entry_offset,
228 sizeof(struct vbios_fct_1x_entry));
229
230 if (!BIOS_GET_FIELD(entry.flags0,
231 NV_VBIOS_FCT_1X_ENTRY_FLAGS0_TYPE)) {
232 continue;
233 }
234
235 freq_controller_data.board_obj.type = (u8)BIOS_GET_FIELD(
236 entry.flags0, NV_VBIOS_FCT_1X_ENTRY_FLAGS0_TYPE);
237
238 ptmp_freq_cntr->controller_id =
239 (u8)BIOS_GET_FIELD(entry.param0,
240 NV_VBIOS_FCT_1X_ENTRY_PARAM0_ID);
241
242 pclk_domain = CLK_CLK_DOMAIN_GET((&g->clk_pmu),
243 (u32)entry.clk_domain_idx);
244 freq_controller_data.freq_controller.clk_domain =
245 pclk_domain->api_domain;
246
247 ptmp_freq_cntr->parts_freq_mode =
248 (u8)BIOS_GET_FIELD(entry.param0,
249 NV_VBIOS_FCT_1X_ENTRY_PARAM0_FREQ_MODE);
250
251 /* Populate PI specific data */
252 ptmp_freq_cntr_pi->slowdown_pct_min =
253 (u8)BIOS_GET_FIELD(entry.param1,
254 NV_VBIOS_FCT_1X_ENTRY_PARAM1_SLOWDOWN_PCT_MIN);
255
256 ptmp_freq_cntr_pi->bpoison =
257 BIOS_GET_FIELD(entry.param1,
258 NV_VBIOS_FCT_1X_ENTRY_PARAM1_POISON);
259
260 ptmp_freq_cntr_pi->prop_gain =
261 (s32)BIOS_GET_FIELD(entry.param2,
262 NV_VBIOS_FCT_1X_ENTRY_PARAM2_PROP_GAIN);
263
264 ptmp_freq_cntr_pi->integ_gain =
265 (s32)BIOS_GET_FIELD(entry.param3,
266 NV_VBIOS_FCT_1X_ENTRY_PARAM3_INTEG_GAIN);
267
268 ptmp_freq_cntr_pi->integ_decay =
269 (s32)BIOS_GET_FIELD(entry.param4,
270 NV_VBIOS_FCT_1X_ENTRY_PARAM4_INTEG_DECAY);
271
272 ptmp_freq_cntr_pi->volt_delta_min =
273 (s32)BIOS_GET_FIELD(entry.param5,
274 NV_VBIOS_FCT_1X_ENTRY_PARAM5_VOLT_DELTA_MIN);
275
276 ptmp_freq_cntr_pi->volt_delta_max =
277 (s32)BIOS_GET_FIELD(entry.param6,
278 NV_VBIOS_FCT_1X_ENTRY_PARAM6_VOLT_DELTA_MAX);
279
280 ptmp_freq_cntr->freq_cap_noise_unaware_vmin_above =
281 (s16)BIOS_GET_FIELD(entry.param7,
282 NV_VBIOS_FCT_1X_ENTRY_PARAM7_FREQ_CAP_VF);
283
284 ptmp_freq_cntr->freq_cap_noise_unaware_vmin_below =
285 (s16)BIOS_GET_FIELD(entry.param7,
286 NV_VBIOS_FCT_1X_ENTRY_PARAM7_FREQ_CAP_VMIN);
287
288 ptmp_freq_cntr->freq_hyst_pos_mhz =
289 (s16)BIOS_GET_FIELD(entry.param8,
290 NV_VBIOS_FCT_1X_ENTRY_PARAM8_FREQ_HYST_POS);
291 ptmp_freq_cntr->freq_hyst_neg_mhz =
292 (s16)BIOS_GET_FIELD(entry.param8,
293 NV_VBIOS_FCT_1X_ENTRY_PARAM8_FREQ_HYST_NEG);
294
295 if (ptmp_freq_cntr_pi->volt_delta_max <
296 ptmp_freq_cntr_pi->volt_delta_min) {
297 goto done;
298 }
299
300 pclk_freq_cntr = clk_clk_freq_controller_construct(g,
301 (void *)&freq_controller_data);
302
303 if (pclk_freq_cntr == NULL) {
304 nvgpu_err(g,
305 "unable to construct clock freq cntlr boardobj for %d",
306 entry_idx);
307 status = -EINVAL;
308 goto done;
309 }
310
311 status = boardobjgrp_objinsert(
312 &pclk_freq_controllers->super.super,
313 (struct boardobj *)pclk_freq_cntr, entry_idx);
314 if (status) {
315 nvgpu_err(g,
316 "unable to insert clock freq cntlr boardobj for");
317 status = -EINVAL;
318 goto done;
319 }
320
321 }
322
323done:
324 return status;
325}
326
327int clk_freq_controller_pmu_setup(struct gk20a *g)
328{
329 int status;
330 struct boardobjgrp *pboardobjgrp = NULL;
331
332 nvgpu_log_info(g, " ");
333
334 pboardobjgrp = &g->clk_pmu.clk_freq_controllers.super.super;
335
336 if (!pboardobjgrp->bconstructed) {
337 return -EINVAL;
338 }
339
340 status = pboardobjgrp->pmuinithandle(g, pboardobjgrp);
341
342 nvgpu_log_info(g, "Done");
343 return status;
344}
345
346static int _clk_freq_controller_devgrp_pmudata_instget(struct gk20a *g,
347 struct nv_pmu_boardobjgrp *pmuboardobjgrp,
348 struct nv_pmu_boardobj **ppboardobjpmudata,
349 u8 idx)
350{
351 struct nv_pmu_clk_clk_freq_controller_boardobj_grp_set *pgrp_set =
352 (struct nv_pmu_clk_clk_freq_controller_boardobj_grp_set *)
353 pmuboardobjgrp;
354
355 nvgpu_log_info(g, " ");
356
357 /*check whether pmuboardobjgrp has a valid boardobj in index*/
358 if (((u32)BIT(idx) &
359 pgrp_set->hdr.data.super.obj_mask.super.data[0]) == 0) {
360 return -EINVAL;
361 }
362
363 *ppboardobjpmudata = (struct nv_pmu_boardobj *)
364 &pgrp_set->objects[idx].data.board_obj;
365 nvgpu_log_info(g, " Done");
366 return 0;
367}
368
369static int _clk_freq_controllers_pmudatainit(struct gk20a *g,
370 struct boardobjgrp *pboardobjgrp,
371 struct nv_pmu_boardobjgrp_super *pboardobjgrppmu)
372{
373 struct nv_pmu_clk_clk_freq_controller_boardobjgrp_set_header *pset =
374 (struct nv_pmu_clk_clk_freq_controller_boardobjgrp_set_header *)
375 pboardobjgrppmu;
376 struct clk_freq_controllers *pcntrs =
377 (struct clk_freq_controllers *)pboardobjgrp;
378 int status = 0;
379
380 status = boardobjgrp_pmudatainit_e32(g, pboardobjgrp, pboardobjgrppmu);
381 if (status) {
382 nvgpu_err(g,
383 "error updating pmu boardobjgrp for clk freq ctrs 0x%x",
384 status);
385 goto done;
386 }
387 pset->sampling_period_ms = pcntrs->sampling_period_ms;
388 pset->volt_policy_idx = pcntrs->volt_policy_idx;
389
390done:
391 return status;
392}
393
394int clk_freq_controller_sw_setup(struct gk20a *g)
395{
396 int status = 0;
397 struct boardobjgrp *pboardobjgrp = NULL;
398 struct clk_freq_controllers *pclk_freq_controllers;
399 struct avfsfllobjs *pfllobjs = &(g->clk_pmu.avfs_fllobjs);
400 struct fll_device *pfll;
401 struct clk_freq_controller *pclkfreqctrl;
402 u8 i;
403 u8 j;
404
405 nvgpu_log_info(g, " ");
406
407 pclk_freq_controllers = &g->clk_pmu.clk_freq_controllers;
408 status = boardobjgrpconstruct_e32(g, &pclk_freq_controllers->super);
409 if (status) {
410 nvgpu_err(g,
411 "error creating boardobjgrp for clk FCT, status - 0x%x",
412 status);
413 goto done;
414 }
415
416 pboardobjgrp = &g->clk_pmu.clk_freq_controllers.super.super;
417
418 pboardobjgrp->pmudatainit = _clk_freq_controllers_pmudatainit;
419 pboardobjgrp->pmudatainstget =
420 _clk_freq_controller_devgrp_pmudata_instget;
421 pboardobjgrp->pmustatusinstget = NULL;
422
423 /* Initialize mask to zero.*/
424 boardobjgrpmask_e32_init(&pclk_freq_controllers->freq_ctrl_load_mask,
425 NULL);
426
427 BOARDOBJGRP_PMU_CONSTRUCT(pboardobjgrp, CLK, CLK_FREQ_CONTROLLER);
428
429 status = BOARDOBJGRP_PMU_CMD_GRP_SET_CONSTRUCT(g, pboardobjgrp,
430 clk, CLK, clk_freq_controller, CLK_FREQ_CONTROLLER);
431 if (status) {
432 nvgpu_err(g,
433 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
434 status);
435 goto done;
436 }
437
438 status = clk_get_freq_controller_table(g, pclk_freq_controllers);
439 if (status) {
440 nvgpu_err(g, "error reading freq controller table - 0x%x",
441 status);
442 goto done;
443 }
444
445 BOARDOBJGRP_FOR_EACH(&(pclk_freq_controllers->super.super),
446 struct clk_freq_controller *, pclkfreqctrl, i) {
447 pfll = NULL;
448 j = 0;
449 BOARDOBJGRP_FOR_EACH(&(pfllobjs->super.super),
450 struct fll_device *, pfll, j) {
451 if (pclkfreqctrl->controller_id == pfll->id) {
452 pfll->freq_ctrl_idx = i;
453 break;
454 }
455 }
456 boardobjgrpmask_bitset(&pclk_freq_controllers->
457 freq_ctrl_load_mask.super, i);
458 }
459done:
460 nvgpu_log_info(g, " done status %x", status);
461 return status;
462}
diff --git a/include/clk/clk_freq_controller.h b/include/clk/clk_freq_controller.h
new file mode 100644
index 0000000..7ae475c
--- /dev/null
+++ b/include/clk/clk_freq_controller.h
@@ -0,0 +1,84 @@
1/*
2* Copyright (c) 2016-2018, 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 NVGPU_CLK_FREQ_CONTROLLER_H
24#define NVGPU_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
81int clk_freq_controller_sw_setup(struct gk20a *g);
82int clk_freq_controller_pmu_setup(struct gk20a *g);
83
84#endif /* NVGPU_CLK_FREQ_CONTROLLER_H */
diff --git a/include/clk/clk_mclk.h b/include/clk/clk_mclk.h
new file mode 100644
index 0000000..47c81d1
--- /dev/null
+++ b/include/clk/clk_mclk.h
@@ -0,0 +1,60 @@
1/*
2* Copyright (c) 2016-2018, 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 NVGPU_CLK_MCLK_H
24#define NVGPU_CLK_MCLK_H
25
26#include <nvgpu/lock.h>
27
28#define GP106_MCLK_LOW_SPEED 0U
29#define GP106_MCLK_MID_SPEED 1U
30#define GP106_MCLK_HIGH_SPEED 2U
31#define GP106_MCLK_NUM_SPEED 3U
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 /* NVGPU_CLK_MCLK_H */
diff --git a/include/clk/clk_prog.c b/include/clk/clk_prog.c
new file mode 100644
index 0000000..9d44d6d
--- /dev/null
+++ b/include/clk/clk_prog.c
@@ -0,0 +1,1152 @@
1/*
2 * Copyright (c) 2016-2020, NVIDIA CORPORATION. All rights reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
21 */
22
23#include <nvgpu/bios.h>
24#include <nvgpu/kmem.h>
25#include <nvgpu/gk20a.h>
26
27#include "clk.h"
28#include "clk_prog.h"
29#include "clk_vf_point.h"
30#include "boardobj/boardobjgrp.h"
31#include "boardobj/boardobjgrp_e32.h"
32#include "gp106/bios_gp106.h"
33#include "ctrl/ctrlclk.h"
34#include "ctrl/ctrlvolt.h"
35
36static struct clk_prog *construct_clk_prog(struct gk20a *g, void *pargs);
37static int devinit_get_clk_prog_table(struct gk20a *g,
38 struct clk_progs *pprogobjs);
39static vf_flatten vfflatten_prog_1x_master;
40static vf_lookup vflookup_prog_1x_master;
41static get_fpoints getfpoints_prog_1x_master;
42static get_slaveclk getslaveclk_prog_1x_master;
43
44static int _clk_progs_pmudatainit(struct gk20a *g,
45 struct boardobjgrp *pboardobjgrp,
46 struct nv_pmu_boardobjgrp_super *pboardobjgrppmu)
47{
48 struct nv_pmu_clk_clk_prog_boardobjgrp_set_header *pset =
49 (struct nv_pmu_clk_clk_prog_boardobjgrp_set_header *)
50 pboardobjgrppmu;
51 struct clk_progs *pprogs = (struct clk_progs *)pboardobjgrp;
52 u32 status = 0;
53
54 status = boardobjgrp_pmudatainit_e32(g, pboardobjgrp, pboardobjgrppmu);
55 if (status) {
56 nvgpu_err(g, "error updating pmu boardobjgrp for clk prog 0x%x",
57 status);
58 goto done;
59 }
60 pset->slave_entry_count = pprogs->slave_entry_count;
61 pset->vf_entry_count = pprogs->vf_entry_count;
62
63done:
64 return status;
65}
66
67static int _clk_progs_pmudata_instget(struct gk20a *g,
68 struct nv_pmu_boardobjgrp *pmuboardobjgrp,
69 struct nv_pmu_boardobj **ppboardobjpmudata,
70 u8 idx)
71{
72 struct nv_pmu_clk_clk_prog_boardobj_grp_set *pgrp_set =
73 (struct nv_pmu_clk_clk_prog_boardobj_grp_set *)pmuboardobjgrp;
74
75 nvgpu_log_info(g, " ");
76
77 /*check whether pmuboardobjgrp has a valid boardobj in index*/
78 if (((u32)BIT(idx) &
79 pgrp_set->hdr.data.super.obj_mask.super.data[0]) == 0) {
80 return -EINVAL;
81 }
82
83 *ppboardobjpmudata = (struct nv_pmu_boardobj *)
84 &pgrp_set->objects[idx].data.board_obj;
85 nvgpu_log_info(g, " Done");
86 return 0;
87}
88
89int clk_prog_sw_setup(struct gk20a *g)
90{
91 int status;
92 struct boardobjgrp *pboardobjgrp = NULL;
93 struct clk_progs *pclkprogobjs;
94
95 nvgpu_log_info(g, " ");
96
97 status = boardobjgrpconstruct_e255(g, &g->clk_pmu.clk_progobjs.super);
98 if (status) {
99 nvgpu_err(g,
100 "error creating boardobjgrp for clk prog, status - 0x%x",
101 status);
102 goto done;
103 }
104
105 pboardobjgrp = &g->clk_pmu.clk_progobjs.super.super;
106 pclkprogobjs = &(g->clk_pmu.clk_progobjs);
107
108 BOARDOBJGRP_PMU_CONSTRUCT(pboardobjgrp, CLK, CLK_PROG);
109
110 status = BOARDOBJGRP_PMU_CMD_GRP_SET_CONSTRUCT(g, pboardobjgrp,
111 clk, CLK, clk_prog, CLK_PROG);
112 if (status) {
113 nvgpu_err(g,
114 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
115 status);
116 goto done;
117 }
118
119 pboardobjgrp->pmudatainit = _clk_progs_pmudatainit;
120 pboardobjgrp->pmudatainstget = _clk_progs_pmudata_instget;
121
122 status = devinit_get_clk_prog_table(g, pclkprogobjs);
123 if (status) {
124 goto done;
125 }
126
127 status = clk_domain_clk_prog_link(g, &g->clk_pmu);
128 if (status) {
129 nvgpu_err(g, "error constructing VF point board objects");
130 goto done;
131 }
132
133
134done:
135 nvgpu_log_info(g, " done status %x", status);
136 return status;
137}
138
139int clk_prog_pmu_setup(struct gk20a *g)
140{
141 int status;
142 struct boardobjgrp *pboardobjgrp = NULL;
143
144 nvgpu_log_info(g, " ");
145
146 pboardobjgrp = &g->clk_pmu.clk_progobjs.super.super;
147
148 if (!pboardobjgrp->bconstructed) {
149 return -EINVAL;
150 }
151
152 status = pboardobjgrp->pmuinithandle(g, pboardobjgrp);
153
154 nvgpu_log_info(g, "Done");
155 return status;
156}
157
158static int devinit_get_clk_prog_table(struct gk20a *g,
159 struct clk_progs *pclkprogobjs)
160{
161 int status = 0;
162 u8 *clkprogs_tbl_ptr = NULL;
163 struct vbios_clock_programming_table_1x_header header = { 0 };
164 struct vbios_clock_programming_table_1x_entry prog = { 0 };
165 struct vbios_clock_programming_table_1x_slave_entry slaveprog = { 0 };
166 struct vbios_clock_programming_table_1x_vf_entry vfprog = { 0 };
167 u8 *entry = NULL;
168 u8 *slaveentry = NULL;
169 u8 *vfentry = NULL;
170 u32 i, j = 0;
171 struct clk_prog *pprog;
172 u8 prog_type;
173 u32 szfmt = VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_SIZE_0D;
174 u32 hszfmt = VBIOS_CLOCK_PROGRAMMING_TABLE_1X_HEADER_SIZE_08;
175 u32 slaveszfmt = VBIOS_CLOCK_PROGRAMMING_TABLE_1X_SLAVE_ENTRY_SIZE_03;
176 u32 vfszfmt = VBIOS_CLOCK_PROGRAMMING_TABLE_1X_VF_ENTRY_SIZE_02;
177 struct ctrl_clk_clk_prog_1x_master_vf_entry
178 vfentries[CTRL_CLK_CLK_PROG_1X_MASTER_VF_ENTRY_MAX_ENTRIES];
179 struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry
180 ratioslaveentries[CTRL_CLK_PROG_1X_MASTER_MAX_SLAVE_ENTRIES];
181 struct ctrl_clk_clk_prog_1x_master_table_slave_entry
182 tableslaveentries[CTRL_CLK_PROG_1X_MASTER_MAX_SLAVE_ENTRIES];
183 union {
184 struct boardobj board_obj;
185 struct clk_prog clkprog;
186 struct clk_prog_1x v1x;
187 struct clk_prog_1x_master v1x_master;
188 struct clk_prog_1x_master_ratio v1x_master_ratio;
189 struct clk_prog_1x_master_table v1x_master_table;
190 } prog_data;
191
192 nvgpu_log_info(g, " ");
193
194 clkprogs_tbl_ptr = (u8 *)nvgpu_bios_get_perf_table_ptrs(g,
195 g->bios.clock_token, CLOCK_PROGRAMMING_TABLE);
196 if (clkprogs_tbl_ptr == NULL) {
197 status = -EINVAL;
198 goto done;
199 }
200
201 memcpy(&header, clkprogs_tbl_ptr, hszfmt);
202 if (header.header_size < hszfmt) {
203 status = -EINVAL;
204 goto done;
205 }
206 hszfmt = header.header_size;
207
208 if (header.entry_size <= VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_SIZE_05) {
209 szfmt = header.entry_size;
210 } else if (header.entry_size <= VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_SIZE_0D) {
211 szfmt = header.entry_size;
212 } else {
213 status = -EINVAL;
214 goto done;
215 }
216
217 if (header.vf_entry_size < vfszfmt) {
218 status = -EINVAL;
219 goto done;
220 }
221 vfszfmt = header.vf_entry_size;
222 if (header.slave_entry_size < slaveszfmt) {
223 status = -EINVAL;
224 goto done;
225 }
226 slaveszfmt = header.slave_entry_size;
227 if (header.vf_entry_count > CTRL_CLK_CLK_DELTA_MAX_VOLT_RAILS) {
228 status = -EINVAL;
229 goto done;
230 }
231
232 pclkprogobjs->slave_entry_count = header.slave_entry_count;
233 pclkprogobjs->vf_entry_count = header.vf_entry_count;
234
235 for (i = 0; i < header.entry_count; i++) {
236 memset(&prog_data, 0x0, (u32)sizeof(prog_data));
237
238 /* Read table entries*/
239 entry = clkprogs_tbl_ptr + hszfmt +
240 (i * (szfmt + (header.slave_entry_count * slaveszfmt) +
241 (header.vf_entry_count * vfszfmt)));
242
243 memcpy(&prog, entry, szfmt);
244 memset(vfentries, 0xFF,
245 sizeof(struct ctrl_clk_clk_prog_1x_master_vf_entry) *
246 CTRL_CLK_CLK_PROG_1X_MASTER_VF_ENTRY_MAX_ENTRIES);
247 memset(ratioslaveentries, 0xFF,
248 sizeof(struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry) *
249 CTRL_CLK_PROG_1X_MASTER_MAX_SLAVE_ENTRIES);
250 memset(tableslaveentries, 0xFF,
251 sizeof(struct ctrl_clk_clk_prog_1x_master_table_slave_entry) *
252 CTRL_CLK_PROG_1X_MASTER_MAX_SLAVE_ENTRIES);
253 prog_type = (u8)BIOS_GET_FIELD(prog.flags0,
254 NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_SOURCE);
255
256 switch (prog_type) {
257 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_SOURCE_PLL:
258 prog_data.v1x.source = CTRL_CLK_PROG_1X_SOURCE_PLL;
259 prog_data.v1x.source_data.pll.pll_idx =
260 (u8)BIOS_GET_FIELD(prog.param0,
261 NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_PARAM0_PLL_PLL_INDEX);
262 prog_data.v1x.source_data.pll.freq_step_size_mhz =
263 (u8)BIOS_GET_FIELD(prog.param1,
264 NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_PARAM1_PLL_FREQ_STEP_SIZE);
265 break;
266
267 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_SOURCE_ONE_SOURCE:
268 prog_data.v1x.source = CTRL_CLK_PROG_1X_SOURCE_ONE_SOURCE;
269 break;
270
271 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_SOURCE_FLL:
272 prog_data.v1x.source = CTRL_CLK_PROG_1X_SOURCE_FLL;
273 break;
274
275 default:
276 nvgpu_err(g, "invalid source %d", prog_type);
277 status = -EINVAL;
278 goto done;
279 }
280
281 prog_data.v1x.freq_max_mhz = (u16)prog.freq_max_mhz;
282
283 prog_type = (u8)BIOS_GET_FIELD(prog.flags0,
284 NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE);
285
286 vfentry = entry + szfmt +
287 header.slave_entry_count * slaveszfmt;
288 slaveentry = entry + szfmt;
289 switch (prog_type) {
290 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE_MASTER_RATIO:
291 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE_MASTER_TABLE:
292 prog_data.v1x_master.b_o_c_o_v_enabled = false;
293 for (j = 0; j < header.vf_entry_count; j++) {
294 memcpy(&vfprog, vfentry, vfszfmt);
295
296 vfentries[j].vfe_idx = (u8)vfprog.vfe_idx;
297 if (CTRL_CLK_PROG_1X_SOURCE_FLL ==
298 prog_data.v1x.source) {
299 vfentries[j].gain_vfe_idx = (u8)BIOS_GET_FIELD(
300 vfprog.param0,
301 NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_VF_ENTRY_PARAM0_FLL_GAIN_VFE_IDX);
302 } else {
303 vfentries[j].gain_vfe_idx = CTRL_BOARDOBJ_IDX_INVALID;
304 }
305 vfentry += vfszfmt;
306 }
307
308 prog_data.v1x_master.p_vf_entries = vfentries;
309
310 for (j = 0; j < header.slave_entry_count; j++) {
311 memcpy(&slaveprog, slaveentry, slaveszfmt);
312
313 switch (prog_type) {
314 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE_MASTER_RATIO:
315 ratioslaveentries[j].clk_dom_idx =
316 (u8)slaveprog.clk_dom_idx;
317 ratioslaveentries[j].ratio = (u8)
318 BIOS_GET_FIELD(slaveprog.param0,
319 NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_SLAVE_ENTRY_PARAM0_MASTER_RATIO_RATIO);
320 break;
321
322 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE_MASTER_TABLE:
323 tableslaveentries[j].clk_dom_idx =
324 (u8)slaveprog.clk_dom_idx;
325 tableslaveentries[j].freq_mhz =
326 (u16)BIOS_GET_FIELD(slaveprog.param0,
327 NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_SLAVE_ENTRY_PARAM0_MASTER_TABLE_FREQ);
328 break;
329 }
330 slaveentry += slaveszfmt;
331 }
332
333 switch (prog_type) {
334 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE_MASTER_RATIO:
335 prog_data.board_obj.type = CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_RATIO;
336 prog_data.v1x_master_ratio.p_slave_entries =
337 ratioslaveentries;
338 break;
339
340 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE_MASTER_TABLE:
341 prog_data.board_obj.type = CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_TABLE;
342
343 prog_data.v1x_master_table.p_slave_entries =
344 tableslaveentries;
345 break;
346
347 }
348 break;
349
350 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE_SLAVE:
351 prog_data.board_obj.type = CTRL_CLK_CLK_PROG_TYPE_1X;
352 break;
353
354
355 default:
356 nvgpu_err(g, "source issue %d", prog_type);
357 status = -EINVAL;
358 goto done;
359 }
360
361 pprog = construct_clk_prog(g, (void *)&prog_data);
362 if (pprog == NULL) {
363 nvgpu_err(g,
364 "error constructing clk_prog boardobj %d", i);
365 status = -EINVAL;
366 goto done;
367 }
368
369 status = boardobjgrp_objinsert(&pclkprogobjs->super.super,
370 (struct boardobj *)pprog, i);
371 if (status) {
372 nvgpu_err(g, "error adding clk_prog boardobj %d", i);
373 status = -EINVAL;
374 goto done;
375 }
376 }
377done:
378 nvgpu_log_info(g, " done status %x", status);
379 return status;
380}
381
382static int _clk_prog_pmudatainit_super(struct gk20a *g,
383 struct boardobj *board_obj_ptr,
384 struct nv_pmu_boardobj *ppmudata)
385{
386 int status = 0;
387
388 nvgpu_log_info(g, " ");
389
390 status = boardobj_pmudatainit_super(g, board_obj_ptr, ppmudata);
391 return status;
392}
393
394static int _clk_prog_pmudatainit_1x(struct gk20a *g,
395 struct boardobj *board_obj_ptr,
396 struct nv_pmu_boardobj *ppmudata)
397{
398 int status = 0;
399 struct clk_prog_1x *pclk_prog_1x;
400 struct nv_pmu_clk_clk_prog_1x_boardobj_set *pset;
401
402 nvgpu_log_info(g, " ");
403
404 status = _clk_prog_pmudatainit_super(g, board_obj_ptr, ppmudata);
405 if (status != 0) {
406 return status;
407 }
408
409 pclk_prog_1x = (struct clk_prog_1x *)board_obj_ptr;
410
411 pset = (struct nv_pmu_clk_clk_prog_1x_boardobj_set *)
412 ppmudata;
413
414 pset->source = pclk_prog_1x->source;
415 pset->freq_max_mhz = pclk_prog_1x->freq_max_mhz;
416 pset->source_data = pclk_prog_1x->source_data;
417
418 return status;
419}
420
421static int _clk_prog_pmudatainit_1x_master(struct gk20a *g,
422 struct boardobj *board_obj_ptr,
423 struct nv_pmu_boardobj *ppmudata)
424{
425 int status = 0;
426 struct clk_prog_1x_master *pclk_prog_1x_master;
427 struct nv_pmu_clk_clk_prog_1x_master_boardobj_set *pset;
428 u32 vfsize = sizeof(struct ctrl_clk_clk_prog_1x_master_vf_entry) *
429 g->clk_pmu.clk_progobjs.vf_entry_count;
430
431 nvgpu_log_info(g, " ");
432
433 status = _clk_prog_pmudatainit_1x(g, board_obj_ptr, ppmudata);
434
435 pclk_prog_1x_master =
436 (struct clk_prog_1x_master *)board_obj_ptr;
437
438 pset = (struct nv_pmu_clk_clk_prog_1x_master_boardobj_set *)
439 ppmudata;
440
441 memcpy(pset->vf_entries, pclk_prog_1x_master->p_vf_entries, vfsize);
442
443 pset->b_o_c_o_v_enabled = pclk_prog_1x_master->b_o_c_o_v_enabled;
444 pset->source_data = pclk_prog_1x_master->source_data;
445
446 memcpy(&pset->deltas, &pclk_prog_1x_master->deltas,
447 (u32) sizeof(struct ctrl_clk_clk_delta));
448
449 return status;
450}
451
452static int _clk_prog_pmudatainit_1x_master_ratio(struct gk20a *g,
453 struct boardobj *board_obj_ptr,
454 struct nv_pmu_boardobj *ppmudata)
455{
456 int status = 0;
457 struct clk_prog_1x_master_ratio *pclk_prog_1x_master_ratio;
458 struct nv_pmu_clk_clk_prog_1x_master_ratio_boardobj_set *pset;
459 u32 slavesize = sizeof(struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry) *
460 g->clk_pmu.clk_progobjs.slave_entry_count;
461
462 nvgpu_log_info(g, " ");
463
464 status = _clk_prog_pmudatainit_1x_master(g, board_obj_ptr, ppmudata);
465 if (status != 0) {
466 return status;
467 }
468
469 pclk_prog_1x_master_ratio =
470 (struct clk_prog_1x_master_ratio *)board_obj_ptr;
471
472 pset = (struct nv_pmu_clk_clk_prog_1x_master_ratio_boardobj_set *)
473 ppmudata;
474
475 memcpy(pset->slave_entries,
476 pclk_prog_1x_master_ratio->p_slave_entries, slavesize);
477
478 return status;
479}
480
481static int _clk_prog_pmudatainit_1x_master_table(struct gk20a *g,
482 struct boardobj *board_obj_ptr,
483 struct nv_pmu_boardobj *ppmudata)
484{
485 int status = 0;
486 struct clk_prog_1x_master_table *pclk_prog_1x_master_table;
487 struct nv_pmu_clk_clk_prog_1x_master_table_boardobj_set *pset;
488 u32 slavesize = sizeof(struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry) *
489 g->clk_pmu.clk_progobjs.slave_entry_count;
490
491 nvgpu_log_info(g, " ");
492
493 status = _clk_prog_pmudatainit_1x_master(g, board_obj_ptr, ppmudata);
494 if (status != 0) {
495 return status;
496 }
497
498 pclk_prog_1x_master_table =
499 (struct clk_prog_1x_master_table *)board_obj_ptr;
500
501 pset = (struct nv_pmu_clk_clk_prog_1x_master_table_boardobj_set *)
502 ppmudata;
503 memcpy(pset->slave_entries,
504 pclk_prog_1x_master_table->p_slave_entries, slavesize);
505
506 return status;
507}
508
509static u32 _clk_prog_1x_master_rail_construct_vf_point(struct gk20a *g,
510 struct clk_pmupstate *pclk,
511 struct clk_prog_1x_master *p1xmaster,
512 struct ctrl_clk_clk_prog_1x_master_vf_entry *p_vf_rail,
513 struct clk_vf_point *p_vf_point_tmp,
514 u8 *p_vf_point_idx)
515{
516 struct clk_vf_point *p_vf_point;
517 u32 status;
518
519 nvgpu_log_info(g, " ");
520
521 p_vf_point = construct_clk_vf_point(g, (void *)p_vf_point_tmp);
522 if (p_vf_point == NULL) {
523 status = -ENOMEM;
524 goto done;
525 }
526 status = pclk->clk_vf_pointobjs.super.super.objinsert(
527 &pclk->clk_vf_pointobjs.super.super,
528 &p_vf_point->super,
529 *p_vf_point_idx);
530 if (status) {
531 goto done;
532 }
533
534 p_vf_rail->vf_point_idx_last = (*p_vf_point_idx)++;
535
536done:
537 nvgpu_log_info(g, "done status %x", status);
538 return status;
539}
540
541static int clk_prog_construct_super(struct gk20a *g,
542 struct boardobj **ppboardobj,
543 u16 size, void *pargs)
544{
545 struct clk_prog *pclkprog;
546 int status = 0;
547
548 status = boardobj_construct_super(g, ppboardobj,
549 size, pargs);
550 if (status) {
551 return -EINVAL;
552 }
553
554 pclkprog = (struct clk_prog *)*ppboardobj;
555
556 pclkprog->super.pmudatainit =
557 _clk_prog_pmudatainit_super;
558 return status;
559}
560
561
562static int clk_prog_construct_1x(struct gk20a *g,
563 struct boardobj **ppboardobj,
564 u16 size, void *pargs)
565{
566 struct boardobj *ptmpobj = (struct boardobj *)pargs;
567 struct clk_prog_1x *pclkprog;
568 struct clk_prog_1x *ptmpprog =
569 (struct clk_prog_1x *)pargs;
570 int status = 0;
571
572 nvgpu_log_info(g, " ");
573 ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_PROG_TYPE_1X);
574 status = clk_prog_construct_super(g, ppboardobj, size, pargs);
575 if (status) {
576 return -EINVAL;
577 }
578
579 pclkprog = (struct clk_prog_1x *)*ppboardobj;
580
581 pclkprog->super.super.pmudatainit =
582 _clk_prog_pmudatainit_1x;
583
584 pclkprog->source = ptmpprog->source;
585 pclkprog->freq_max_mhz = ptmpprog->freq_max_mhz;
586 pclkprog->source_data = ptmpprog->source_data;
587
588 return status;
589}
590
591static int clk_prog_construct_1x_master(struct gk20a *g,
592 struct boardobj **ppboardobj,
593 u16 size, void *pargs)
594{
595 struct boardobj *ptmpobj = (struct boardobj *)pargs;
596 struct clk_prog_1x_master *pclkprog;
597 struct clk_prog_1x_master *ptmpprog =
598 (struct clk_prog_1x_master *)pargs;
599 int status = 0;
600 u32 vfsize = sizeof(struct ctrl_clk_clk_prog_1x_master_vf_entry) *
601 g->clk_pmu.clk_progobjs.vf_entry_count;
602 u8 railidx;
603
604 nvgpu_log_info(g, " type - %x", BOARDOBJ_GET_TYPE(pargs));
605
606 ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_PROG_TYPE_1X_MASTER);
607 status = clk_prog_construct_1x(g, ppboardobj, size, pargs);
608 if (status) {
609 return -EINVAL;
610 }
611
612 pclkprog = (struct clk_prog_1x_master *)*ppboardobj;
613
614 pclkprog->super.super.super.pmudatainit =
615 _clk_prog_pmudatainit_1x_master;
616
617 pclkprog->vfflatten =
618 vfflatten_prog_1x_master;
619
620 pclkprog->vflookup =
621 vflookup_prog_1x_master;
622
623 pclkprog->getfpoints =
624 getfpoints_prog_1x_master;
625
626 pclkprog->getslaveclk =
627 getslaveclk_prog_1x_master;
628
629 pclkprog->p_vf_entries = (struct ctrl_clk_clk_prog_1x_master_vf_entry *)
630 nvgpu_kzalloc(g, vfsize);
631 if (!pclkprog->p_vf_entries)
632 return -ENOMEM;
633
634 memcpy(pclkprog->p_vf_entries, ptmpprog->p_vf_entries, vfsize);
635
636 pclkprog->b_o_c_o_v_enabled = ptmpprog->b_o_c_o_v_enabled;
637
638 for (railidx = 0;
639 railidx < g->clk_pmu.clk_progobjs.vf_entry_count;
640 railidx++) {
641 pclkprog->p_vf_entries[railidx].vf_point_idx_first =
642 CTRL_CLK_CLK_VF_POINT_IDX_INVALID;
643 pclkprog->p_vf_entries[railidx].vf_point_idx_last =
644 CTRL_CLK_CLK_VF_POINT_IDX_INVALID;
645 }
646
647 return status;
648}
649
650static int clk_prog_construct_1x_master_ratio(struct gk20a *g,
651 struct boardobj **ppboardobj,
652 u16 size, void *pargs)
653{
654 struct boardobj *ptmpobj = (struct boardobj *)pargs;
655 struct clk_prog_1x_master_ratio *pclkprog;
656 struct clk_prog_1x_master_ratio *ptmpprog =
657 (struct clk_prog_1x_master_ratio *)pargs;
658 int status = 0;
659 u32 slavesize = sizeof(struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry) *
660 g->clk_pmu.clk_progobjs.slave_entry_count;
661
662 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_RATIO) {
663 return -EINVAL;
664 }
665
666 ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_RATIO);
667 status = clk_prog_construct_1x_master(g, ppboardobj, size, pargs);
668 if (status) {
669 return -EINVAL;
670 }
671
672 pclkprog = (struct clk_prog_1x_master_ratio *)*ppboardobj;
673
674 pclkprog->super.super.super.super.pmudatainit =
675 _clk_prog_pmudatainit_1x_master_ratio;
676
677 pclkprog->p_slave_entries =
678 (struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry *)
679 nvgpu_kzalloc(g, slavesize);
680 if (!pclkprog->p_slave_entries) {
681 return -ENOMEM;
682 }
683
684 memset(pclkprog->p_slave_entries, CTRL_CLK_CLK_DOMAIN_INDEX_INVALID,
685 slavesize);
686
687 memcpy(pclkprog->p_slave_entries, ptmpprog->p_slave_entries, slavesize);
688
689 return status;
690}
691
692static int clk_prog_construct_1x_master_table(struct gk20a *g,
693 struct boardobj **ppboardobj,
694 u16 size, void *pargs)
695{
696 struct boardobj *ptmpobj = (struct boardobj *)pargs;
697 struct clk_prog_1x_master_table *pclkprog;
698 struct clk_prog_1x_master_table *ptmpprog =
699 (struct clk_prog_1x_master_table *)pargs;
700 int status = 0;
701 u32 slavesize = sizeof(struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry) *
702 g->clk_pmu.clk_progobjs.slave_entry_count;
703
704 nvgpu_log_info(g, "type - %x", BOARDOBJ_GET_TYPE(pargs));
705
706 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_TABLE) {
707 return -EINVAL;
708 }
709
710 ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_TABLE);
711 status = clk_prog_construct_1x_master(g, ppboardobj, size, pargs);
712 if (status) {
713 return -EINVAL;
714 }
715
716 pclkprog = (struct clk_prog_1x_master_table *)*ppboardobj;
717
718 pclkprog->super.super.super.super.pmudatainit =
719 _clk_prog_pmudatainit_1x_master_table;
720
721 pclkprog->p_slave_entries =
722 (struct ctrl_clk_clk_prog_1x_master_table_slave_entry *)
723 nvgpu_kzalloc(g, slavesize);
724
725 if (!pclkprog->p_slave_entries) {
726 status = -ENOMEM;
727 goto exit;
728 }
729
730 memset(pclkprog->p_slave_entries, CTRL_CLK_CLK_DOMAIN_INDEX_INVALID,
731 slavesize);
732
733 memcpy(pclkprog->p_slave_entries, ptmpprog->p_slave_entries, slavesize);
734
735exit:
736 if (status) {
737 (*ppboardobj)->destruct(*ppboardobj);
738 }
739
740 return status;
741}
742
743static struct clk_prog *construct_clk_prog(struct gk20a *g, void *pargs)
744{
745 struct boardobj *board_obj_ptr = NULL;
746 int status;
747
748 nvgpu_log_info(g, " type - %x", BOARDOBJ_GET_TYPE(pargs));
749 switch (BOARDOBJ_GET_TYPE(pargs)) {
750 case CTRL_CLK_CLK_PROG_TYPE_1X:
751 status = clk_prog_construct_1x(g, &board_obj_ptr,
752 sizeof(struct clk_prog_1x), pargs);
753 break;
754
755 case CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_TABLE:
756 status = clk_prog_construct_1x_master_table(g, &board_obj_ptr,
757 sizeof(struct clk_prog_1x_master_table), pargs);
758 break;
759
760 case CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_RATIO:
761 status = clk_prog_construct_1x_master_ratio(g, &board_obj_ptr,
762 sizeof(struct clk_prog_1x_master_ratio), pargs);
763 break;
764
765 default:
766 return NULL;
767 }
768
769 if (status) {
770 if (board_obj_ptr) {
771 board_obj_ptr->destruct(board_obj_ptr);
772 }
773 return NULL;
774 }
775
776 nvgpu_log_info(g, " Done");
777
778 return (struct clk_prog *)board_obj_ptr;
779}
780
781static u32 vfflatten_prog_1x_master(struct gk20a *g,
782 struct clk_pmupstate *pclk,
783 struct clk_prog_1x_master *p1xmaster,
784 u8 clk_domain_idx, u16 *pfreqmaxlastmhz)
785{
786 struct ctrl_clk_clk_prog_1x_master_vf_entry *p_vf_rail;
787 union {
788 struct boardobj board_obj;
789 struct clk_vf_point vf_point;
790 struct clk_vf_point_freq freq;
791 struct clk_vf_point_volt volt;
792 } vf_point_data;
793 u32 status = 0;
794 u8 step_count;
795 u8 freq_step_size_mhz = 0;
796 u8 vf_point_idx;
797 u8 vf_rail_idx;
798
799 nvgpu_log_info(g, " ");
800 memset(&vf_point_data, 0x0, sizeof(vf_point_data));
801
802 vf_point_idx = BOARDOBJGRP_NEXT_EMPTY_IDX(
803 &pclk->clk_vf_pointobjs.super.super);
804
805 for (vf_rail_idx = 0;
806 vf_rail_idx < pclk->clk_progobjs.vf_entry_count;
807 vf_rail_idx++) {
808 u32 voltage_min_uv;
809 u32 voltage_step_size_uv;
810 u8 i;
811
812 p_vf_rail = &p1xmaster->p_vf_entries[vf_rail_idx];
813 if (p_vf_rail->vfe_idx == CTRL_BOARDOBJ_IDX_INVALID) {
814 continue;
815 }
816
817 p_vf_rail->vf_point_idx_first = vf_point_idx;
818
819 vf_point_data.vf_point.vfe_equ_idx = p_vf_rail->vfe_idx;
820 vf_point_data.vf_point.volt_rail_idx = vf_rail_idx;
821
822 step_count = 0;
823
824 switch (p1xmaster->super.source) {
825 case CTRL_CLK_PROG_1X_SOURCE_PLL:
826 freq_step_size_mhz =
827 p1xmaster->super.source_data.pll.freq_step_size_mhz;
828 step_count = (freq_step_size_mhz == 0) ? 0 :
829 (p1xmaster->super.freq_max_mhz - *pfreqmaxlastmhz - 1) /
830 freq_step_size_mhz;
831 /* Intentional fall-through.*/
832
833 case CTRL_CLK_PROG_1X_SOURCE_ONE_SOURCE:
834 vf_point_data.board_obj.type =
835 CTRL_CLK_CLK_VF_POINT_TYPE_FREQ;
836 do {
837 clkvfpointfreqmhzset(g, &vf_point_data.vf_point,
838 p1xmaster->super.freq_max_mhz -
839 step_count * freq_step_size_mhz);
840
841 status = _clk_prog_1x_master_rail_construct_vf_point(g, pclk,
842 p1xmaster, p_vf_rail,
843 &vf_point_data.vf_point, &vf_point_idx);
844 if (status) {
845 goto done;
846 }
847 } while (step_count-- > 0);
848 break;
849
850 case CTRL_CLK_PROG_1X_SOURCE_FLL:
851 voltage_min_uv = CLK_FLL_LUT_MIN_VOLTAGE_UV(pclk);
852 voltage_step_size_uv = CLK_FLL_LUT_STEP_SIZE_UV(pclk);
853 step_count = CLK_FLL_LUT_VF_NUM_ENTRIES(pclk);
854
855 /* FLL sources use a voltage-based VF_POINT.*/
856 vf_point_data.board_obj.type =
857 CTRL_CLK_CLK_VF_POINT_TYPE_VOLT;
858 for (i = 0; i < step_count; i++) {
859 vf_point_data.volt.source_voltage_uv =
860 voltage_min_uv + i * voltage_step_size_uv;
861
862 status = _clk_prog_1x_master_rail_construct_vf_point(g, pclk,
863 p1xmaster, p_vf_rail,
864 &vf_point_data.vf_point, &vf_point_idx);
865 if (status) {
866 goto done;
867 }
868 }
869 break;
870 }
871 }
872
873 *pfreqmaxlastmhz = p1xmaster->super.freq_max_mhz;
874
875done:
876 nvgpu_log_info(g, "done status %x", status);
877 return status;
878}
879
880static u32 vflookup_prog_1x_master
881(
882 struct gk20a *g,
883 struct clk_pmupstate *pclk,
884 struct clk_prog_1x_master *p1xmaster,
885 u8 *slave_clk_domain,
886 u16 *pclkmhz,
887 u32 *pvoltuv,
888 u8 rail
889)
890{
891 int j;
892 struct ctrl_clk_clk_prog_1x_master_vf_entry
893 *pvfentry;
894 struct clk_vf_point *pvfpoint;
895 struct clk_progs *pclkprogobjs;
896 struct clk_prog_1x_master_ratio *p1xmasterratio;
897 u16 clkmhz;
898 u32 voltuv;
899 u8 slaveentrycount;
900 int i;
901 struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry *pslaveents;
902
903 if ((*pclkmhz != 0) && (*pvoltuv != 0)) {
904 return -EINVAL;
905 }
906
907 pclkprogobjs = &(pclk->clk_progobjs);
908
909 slaveentrycount = pclkprogobjs->slave_entry_count;
910
911 if (pclkprogobjs->vf_entry_count >
912 CTRL_CLK_CLK_PROG_1X_MASTER_VF_ENTRY_MAX_ENTRIES) {
913 return -EINVAL;
914 }
915
916 if (rail >= pclkprogobjs->vf_entry_count) {
917 return -EINVAL;
918 }
919
920 pvfentry = p1xmaster->p_vf_entries;
921
922 pvfentry = (struct ctrl_clk_clk_prog_1x_master_vf_entry *)(
923 (u8 *)pvfentry +
924 (sizeof(struct ctrl_clk_clk_prog_1x_master_vf_entry) *
925 rail));
926
927 clkmhz = *pclkmhz;
928 voltuv = *pvoltuv;
929
930 /*if domain is slave domain and freq is input
931 then derive master clk */
932 if ((slave_clk_domain != NULL) && (*pclkmhz != 0)) {
933 if (p1xmaster->super.super.super.implements(g,
934 &p1xmaster->super.super.super,
935 CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_RATIO)) {
936
937 p1xmasterratio =
938 (struct clk_prog_1x_master_ratio *)p1xmaster;
939 pslaveents = p1xmasterratio->p_slave_entries;
940 for (i = 0; i < slaveentrycount; i++) {
941 if (pslaveents->clk_dom_idx ==
942 *slave_clk_domain) {
943 break;
944 }
945 pslaveents++;
946 }
947 if (i == slaveentrycount) {
948 return -EINVAL;
949 }
950 clkmhz = (clkmhz * 100)/pslaveents->ratio;
951 } else {
952 /* only support ratio for now */
953 return -EINVAL;
954 }
955 }
956
957 /* if both volt and clks are zero simply print*/
958 if ((*pvoltuv == 0) && (*pclkmhz == 0)) {
959 for (j = pvfentry->vf_point_idx_first;
960 j <= pvfentry->vf_point_idx_last; j++) {
961 pvfpoint = CLK_CLK_VF_POINT_GET(pclk, j);
962 nvgpu_err(g, "v %x c %x",
963 clkvfpointvoltageuvget(g, pvfpoint),
964 clkvfpointfreqmhzget(g, pvfpoint));
965 }
966 return -EINVAL;
967 }
968 /* start looking up f for v for v for f */
969 /* looking for volt? */
970 if (*pvoltuv == 0) {
971 pvfpoint = CLK_CLK_VF_POINT_GET(pclk,
972 pvfentry->vf_point_idx_last);
973 /* above range? */
974 if (clkmhz > clkvfpointfreqmhzget(g, pvfpoint)) {
975 return -EINVAL;
976 }
977
978 for (j = pvfentry->vf_point_idx_last;
979 j >= pvfentry->vf_point_idx_first; j--) {
980 pvfpoint = CLK_CLK_VF_POINT_GET(pclk, j);
981 if (clkmhz <= clkvfpointfreqmhzget(g, pvfpoint)) {
982 voltuv = clkvfpointvoltageuvget(g, pvfpoint);
983 } else {
984 break;
985 }
986 }
987 } else { /* looking for clk? */
988
989 pvfpoint = CLK_CLK_VF_POINT_GET(pclk,
990 pvfentry->vf_point_idx_first);
991 /* below range? */
992 if (voltuv < clkvfpointvoltageuvget(g, pvfpoint)) {
993 return -EINVAL;
994 }
995
996 for (j = pvfentry->vf_point_idx_first;
997 j <= pvfentry->vf_point_idx_last; j++) {
998 pvfpoint = CLK_CLK_VF_POINT_GET(pclk, j);
999 if (voltuv >= clkvfpointvoltageuvget(g, pvfpoint)) {
1000 clkmhz = clkvfpointfreqmhzget(g, pvfpoint);
1001 } else {
1002 break;
1003 }
1004 }
1005 }
1006
1007 /*if domain is slave domain and freq was looked up
1008 then derive slave clk */
1009 if ((slave_clk_domain != NULL) && (*pclkmhz == 0)) {
1010 if (p1xmaster->super.super.super.implements(g,
1011 &p1xmaster->super.super.super,
1012 CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_RATIO)) {
1013
1014 p1xmasterratio =
1015 (struct clk_prog_1x_master_ratio *)p1xmaster;
1016 pslaveents = p1xmasterratio->p_slave_entries;
1017 for (i = 0; i < slaveentrycount; i++) {
1018 if (pslaveents->clk_dom_idx ==
1019 *slave_clk_domain) {
1020 break;
1021 }
1022 pslaveents++;
1023 }
1024 if (i == slaveentrycount) {
1025 return -EINVAL;
1026 }
1027 clkmhz = (clkmhz * pslaveents->ratio)/100;
1028 } else {
1029 /* only support ratio for now */
1030 return -EINVAL;
1031 }
1032 }
1033 *pclkmhz = clkmhz;
1034 *pvoltuv = voltuv;
1035 if ((clkmhz == 0) || (voltuv == 0)) {
1036 return -EINVAL;
1037 }
1038 return 0;
1039}
1040
1041static u32 getfpoints_prog_1x_master
1042(
1043 struct gk20a *g,
1044 struct clk_pmupstate *pclk,
1045 struct clk_prog_1x_master *p1xmaster,
1046 u32 *pfpointscount,
1047 u16 **ppfreqpointsinmhz,
1048 u8 rail
1049)
1050{
1051
1052 struct ctrl_clk_clk_prog_1x_master_vf_entry
1053 *pvfentry;
1054 struct clk_vf_point *pvfpoint;
1055 struct clk_progs *pclkprogobjs;
1056 u8 j;
1057 u32 fpointscount = 0;
1058
1059 if (pfpointscount == NULL) {
1060 return -EINVAL;
1061 }
1062
1063 pclkprogobjs = &(pclk->clk_progobjs);
1064
1065 if (pclkprogobjs->vf_entry_count >
1066 CTRL_CLK_CLK_PROG_1X_MASTER_VF_ENTRY_MAX_ENTRIES) {
1067 return -EINVAL;
1068 }
1069
1070 if (rail >= pclkprogobjs->vf_entry_count) {
1071 return -EINVAL;
1072 }
1073
1074 pvfentry = p1xmaster->p_vf_entries;
1075
1076 pvfentry = (struct ctrl_clk_clk_prog_1x_master_vf_entry *)(
1077 (u8 *)pvfentry +
1078 (sizeof(struct ctrl_clk_clk_prog_1x_master_vf_entry) *
1079 (rail+1)));
1080
1081 fpointscount = pvfentry->vf_point_idx_last -
1082 pvfentry->vf_point_idx_first + 1;
1083
1084 /* if pointer for freq data is NULL simply return count */
1085 if (*ppfreqpointsinmhz == NULL) {
1086 goto done;
1087 }
1088
1089 if (fpointscount > *pfpointscount) {
1090 return -ENOMEM;
1091 }
1092 for (j = pvfentry->vf_point_idx_first;
1093 j <= pvfentry->vf_point_idx_last; j++) {
1094 pvfpoint = CLK_CLK_VF_POINT_GET(pclk, j);
1095 **ppfreqpointsinmhz = clkvfpointfreqmhzget(g, pvfpoint);
1096 (*ppfreqpointsinmhz)++;
1097 }
1098done:
1099 *pfpointscount = fpointscount;
1100 return 0;
1101}
1102
1103static int getslaveclk_prog_1x_master(struct gk20a *g,
1104 struct clk_pmupstate *pclk,
1105 struct clk_prog_1x_master *p1xmaster,
1106 u8 slave_clk_domain,
1107 u16 *pclkmhz,
1108 u16 masterclkmhz
1109)
1110{
1111 struct clk_progs *pclkprogobjs;
1112 struct clk_prog_1x_master_ratio *p1xmasterratio;
1113 u8 slaveentrycount;
1114 u8 i;
1115 struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry *pslaveents;
1116
1117 if (pclkmhz == NULL) {
1118 return -EINVAL;
1119 }
1120
1121 if (masterclkmhz == 0) {
1122 return -EINVAL;
1123 }
1124
1125 *pclkmhz = 0;
1126 pclkprogobjs = &(pclk->clk_progobjs);
1127
1128 slaveentrycount = pclkprogobjs->slave_entry_count;
1129
1130 if (p1xmaster->super.super.super.implements(g,
1131 &p1xmaster->super.super.super,
1132 CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_RATIO)) {
1133 p1xmasterratio =
1134 (struct clk_prog_1x_master_ratio *)p1xmaster;
1135 pslaveents = p1xmasterratio->p_slave_entries;
1136 for (i = 0; i < slaveentrycount; i++) {
1137 if (pslaveents->clk_dom_idx ==
1138 slave_clk_domain) {
1139 break;
1140 }
1141 pslaveents++;
1142 }
1143 if (i == slaveentrycount) {
1144 return -EINVAL;
1145 }
1146 *pclkmhz = (masterclkmhz * pslaveents->ratio)/100;
1147 } else {
1148 /* only support ratio for now */
1149 return -EINVAL;
1150 }
1151 return 0;
1152}
diff --git a/include/clk/clk_prog.h b/include/clk/clk_prog.h
new file mode 100644
index 0000000..af6368f
--- /dev/null
+++ b/include/clk/clk_prog.h
@@ -0,0 +1,100 @@
1/*
2* Copyright (c) 2016-2018, 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 NVGPU_CLK_PROG_H
24#define NVGPU_CLK_PROG_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
32int clk_prog_sw_setup(struct gk20a *g);
33int 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 /* NVGPU_CLK_PROG_H */
diff --git a/include/clk/clk_vf_point.c b/include/clk/clk_vf_point.c
new file mode 100644
index 0000000..96413c8
--- /dev/null
+++ b/include/clk/clk_vf_point.c
@@ -0,0 +1,433 @@
1/*
2 * Copyright (c) 2016-2018, 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/gk20a.h>
24
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 int _clk_vf_point_pmudatainit_super(struct gk20a *g, struct boardobj
33 *board_obj_ptr, struct nv_pmu_boardobj *ppmudata);
34
35static int _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 int _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 nvgpu_log_info(g, " ");
63
64 /*check whether pmuboardobjgrp has a valid boardobj in index*/
65 if (idx >= CTRL_BOARDOBJGRP_E255_MAX_OBJECTS) {
66 return -EINVAL;
67 }
68
69 *ppboardobjpmudata = (struct nv_pmu_boardobj *)
70 &pgrp_set->objects[idx].data.board_obj;
71 nvgpu_log_info(g, " Done");
72 return 0;
73}
74
75static int _clk_vf_points_pmustatus_instget(struct gk20a *g,
76 void *pboardobjgrppmu,
77 struct nv_pmu_boardobj_query **ppboardobjpmustatus,
78 u8 idx)
79{
80 struct nv_pmu_clk_clk_vf_point_boardobj_grp_get_status *pgrp_get_status =
81 (struct nv_pmu_clk_clk_vf_point_boardobj_grp_get_status *)
82 pboardobjgrppmu;
83
84 /*check whether pmuboardobjgrp has a valid boardobj in index*/
85 if (idx >= CTRL_BOARDOBJGRP_E255_MAX_OBJECTS) {
86 return -EINVAL;
87 }
88
89 *ppboardobjpmustatus = (struct nv_pmu_boardobj_query *)
90 &pgrp_get_status->objects[idx].data.board_obj;
91 return 0;
92}
93
94int clk_vf_point_sw_setup(struct gk20a *g)
95{
96 int status;
97 struct boardobjgrp *pboardobjgrp = NULL;
98
99 nvgpu_log_info(g, " ");
100
101 status = boardobjgrpconstruct_e255(g, &g->clk_pmu.clk_vf_pointobjs.super);
102 if (status) {
103 nvgpu_err(g,
104 "error creating boardobjgrp for clk vfpoint, status - 0x%x",
105 status);
106 goto done;
107 }
108
109 pboardobjgrp = &g->clk_pmu.clk_vf_pointobjs.super.super;
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 nvgpu_log_info(g, " done status %x", status);
138 return status;
139}
140
141int clk_vf_point_pmu_setup(struct gk20a *g)
142{
143 int status;
144 struct boardobjgrp *pboardobjgrp = NULL;
145
146 nvgpu_log_info(g, " ");
147
148 pboardobjgrp = &g->clk_pmu.clk_vf_pointobjs.super.super;
149
150 if (!pboardobjgrp->bconstructed) {
151 return -EINVAL;
152 }
153
154 status = pboardobjgrp->pmuinithandle(g, pboardobjgrp);
155
156 nvgpu_log_info(g, "Done");
157 return status;
158}
159
160static int clk_vf_point_construct_super(struct gk20a *g,
161 struct boardobj **ppboardobj,
162 u16 size, void *pargs)
163{
164 struct clk_vf_point *pclkvfpoint;
165 struct clk_vf_point *ptmpvfpoint =
166 (struct clk_vf_point *)pargs;
167 int status = 0;
168
169 status = boardobj_construct_super(g, ppboardobj,
170 size, pargs);
171 if (status) {
172 return -EINVAL;
173 }
174
175 pclkvfpoint = (struct clk_vf_point *)*ppboardobj;
176
177 pclkvfpoint->super.pmudatainit =
178 _clk_vf_point_pmudatainit_super;
179
180 pclkvfpoint->vfe_equ_idx = ptmpvfpoint->vfe_equ_idx;
181 pclkvfpoint->volt_rail_idx = ptmpvfpoint->volt_rail_idx;
182
183 return status;
184}
185
186static int _clk_vf_point_pmudatainit_volt(struct gk20a *g,
187 struct boardobj *board_obj_ptr,
188 struct nv_pmu_boardobj *ppmudata)
189{
190 int status = 0;
191 struct clk_vf_point_volt *pclk_vf_point_volt;
192 struct nv_pmu_clk_clk_vf_point_volt_boardobj_set *pset;
193
194 nvgpu_log_info(g, " ");
195
196 status = _clk_vf_point_pmudatainit_super(g, board_obj_ptr, ppmudata);
197 if (status != 0) {
198 return status;
199 }
200
201 pclk_vf_point_volt =
202 (struct clk_vf_point_volt *)board_obj_ptr;
203
204 pset = (struct nv_pmu_clk_clk_vf_point_volt_boardobj_set *)
205 ppmudata;
206
207 pset->source_voltage_uv = pclk_vf_point_volt->source_voltage_uv;
208 pset->freq_delta.data = pclk_vf_point_volt->freq_delta.data;
209 pset->freq_delta.type = pclk_vf_point_volt->freq_delta.type;
210
211 return status;
212}
213
214static int _clk_vf_point_pmudatainit_freq(struct gk20a *g,
215 struct boardobj *board_obj_ptr,
216 struct nv_pmu_boardobj *ppmudata)
217{
218 int status = 0;
219 struct clk_vf_point_freq *pclk_vf_point_freq;
220 struct nv_pmu_clk_clk_vf_point_freq_boardobj_set *pset;
221
222 nvgpu_log_info(g, " ");
223
224 status = _clk_vf_point_pmudatainit_super(g, board_obj_ptr, ppmudata);
225 if (status != 0) {
226 return status;
227 }
228
229 pclk_vf_point_freq =
230 (struct clk_vf_point_freq *)board_obj_ptr;
231
232 pset = (struct nv_pmu_clk_clk_vf_point_freq_boardobj_set *)
233 ppmudata;
234
235 pset->freq_mhz =
236 clkvfpointfreqmhzget(g, &pclk_vf_point_freq->super);
237
238 pset->volt_delta_uv = pclk_vf_point_freq->volt_delta_uv;
239
240 return status;
241}
242
243static int clk_vf_point_construct_volt(struct gk20a *g,
244 struct boardobj **ppboardobj,
245 u16 size, void *pargs)
246{
247 struct boardobj *ptmpobj = (struct boardobj *)pargs;
248 struct clk_vf_point_volt *pclkvfpoint;
249 struct clk_vf_point_volt *ptmpvfpoint =
250 (struct clk_vf_point_volt *)pargs;
251 int status = 0;
252
253 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_CLK_CLK_VF_POINT_TYPE_VOLT) {
254 return -EINVAL;
255 }
256
257 ptmpobj->type_mask = BIT(CTRL_CLK_CLK_VF_POINT_TYPE_VOLT);
258 status = clk_vf_point_construct_super(g, ppboardobj, size, pargs);
259 if (status) {
260 return -EINVAL;
261 }
262
263 pclkvfpoint = (struct clk_vf_point_volt *)*ppboardobj;
264
265 pclkvfpoint->super.super.pmudatainit =
266 _clk_vf_point_pmudatainit_volt;
267
268 pclkvfpoint->source_voltage_uv = ptmpvfpoint->source_voltage_uv;
269 pclkvfpoint->freq_delta = ptmpvfpoint->freq_delta;
270
271 return status;
272}
273
274static int clk_vf_point_construct_freq(struct gk20a *g,
275 struct boardobj **ppboardobj,
276 u16 size, void *pargs)
277{
278 struct boardobj *ptmpobj = (struct boardobj *)pargs;
279 struct clk_vf_point_freq *pclkvfpoint;
280 struct clk_vf_point_freq *ptmpvfpoint =
281 (struct clk_vf_point_freq *)pargs;
282 int status = 0;
283
284 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_CLK_CLK_VF_POINT_TYPE_FREQ) {
285 return -EINVAL;
286 }
287
288 ptmpobj->type_mask = BIT(CTRL_CLK_CLK_VF_POINT_TYPE_FREQ);
289 status = clk_vf_point_construct_super(g, ppboardobj, size, pargs);
290 if (status) {
291 return -EINVAL;
292 }
293
294 pclkvfpoint = (struct clk_vf_point_freq *)*ppboardobj;
295
296 pclkvfpoint->super.super.pmudatainit =
297 _clk_vf_point_pmudatainit_freq;
298
299 clkvfpointfreqmhzset(g, &pclkvfpoint->super,
300 clkvfpointfreqmhzget(g, &ptmpvfpoint->super));
301
302 return status;
303}
304
305struct clk_vf_point *construct_clk_vf_point(struct gk20a *g, void *pargs)
306{
307 struct boardobj *board_obj_ptr = NULL;
308 int status;
309
310 nvgpu_log_info(g, " ");
311 switch (BOARDOBJ_GET_TYPE(pargs)) {
312 case CTRL_CLK_CLK_VF_POINT_TYPE_FREQ:
313 status = clk_vf_point_construct_freq(g, &board_obj_ptr,
314 sizeof(struct clk_vf_point_freq), pargs);
315 break;
316
317 case CTRL_CLK_CLK_VF_POINT_TYPE_VOLT:
318 status = clk_vf_point_construct_volt(g, &board_obj_ptr,
319 sizeof(struct clk_vf_point_volt), pargs);
320 break;
321
322 default:
323 return NULL;
324 }
325
326 if (status) {
327 return NULL;
328 }
329
330 nvgpu_log_info(g, " Done");
331
332 return (struct clk_vf_point *)board_obj_ptr;
333}
334
335static int _clk_vf_point_pmudatainit_super(struct gk20a *g,
336 struct boardobj *board_obj_ptr,
337 struct nv_pmu_boardobj *ppmudata)
338{
339 int status = 0;
340 struct clk_vf_point *pclk_vf_point;
341 struct nv_pmu_clk_clk_vf_point_boardobj_set *pset;
342
343 nvgpu_log_info(g, " ");
344
345 status = boardobj_pmudatainit_super(g, board_obj_ptr, ppmudata);
346 if (status != 0) {
347 return status;
348 }
349
350 pclk_vf_point =
351 (struct clk_vf_point *)board_obj_ptr;
352
353 pset = (struct nv_pmu_clk_clk_vf_point_boardobj_set *)
354 ppmudata;
355
356
357 pset->vfe_equ_idx = pclk_vf_point->vfe_equ_idx;
358 pset->volt_rail_idx = pclk_vf_point->volt_rail_idx;
359 return status;
360}
361
362
363static int clk_vf_point_update(struct gk20a *g,
364 struct boardobj *board_obj_ptr,
365 struct nv_pmu_boardobj *ppmudata)
366{
367 struct clk_vf_point *pclk_vf_point;
368 struct nv_pmu_clk_clk_vf_point_boardobj_get_status *pstatus;
369
370 nvgpu_log_info(g, " ");
371
372
373 pclk_vf_point =
374 (struct clk_vf_point *)board_obj_ptr;
375
376 pstatus = (struct nv_pmu_clk_clk_vf_point_boardobj_get_status *)
377 ppmudata;
378
379 if (pstatus->super.type != pclk_vf_point->super.type) {
380 nvgpu_err(g,
381 "pmu data and boardobj type not matching");
382 return -EINVAL;
383 }
384 /* now copy VF pair */
385 memcpy(&pclk_vf_point->pair, &pstatus->pair,
386 sizeof(struct ctrl_clk_vf_pair));
387 return 0;
388}
389
390/*get latest vf point data from PMU */
391int clk_vf_point_cache(struct gk20a *g)
392{
393
394 struct clk_vf_points *pclk_vf_points;
395 struct boardobjgrp *pboardobjgrp;
396 struct boardobjgrpmask *pboardobjgrpmask;
397 struct nv_pmu_boardobjgrp_super *pboardobjgrppmu;
398 struct boardobj *pboardobj = NULL;
399 struct nv_pmu_boardobj_query *pboardobjpmustatus = NULL;
400 int status;
401 u8 index;
402
403 nvgpu_log_info(g, " ");
404 pclk_vf_points = &g->clk_pmu.clk_vf_pointobjs;
405 pboardobjgrp = &pclk_vf_points->super.super;
406 pboardobjgrpmask = &pclk_vf_points->super.mask.super;
407
408 status = pboardobjgrp->pmugetstatus(g, pboardobjgrp, pboardobjgrpmask);
409 if (status) {
410 nvgpu_err(g, "err getting boardobjs from pmu");
411 return status;
412 }
413 pboardobjgrppmu = pboardobjgrp->pmu.getstatus.buf;
414
415 BOARDOBJGRP_FOR_EACH(pboardobjgrp, struct boardobj*, pboardobj, index) {
416 status = pboardobjgrp->pmustatusinstget(g,
417 (struct nv_pmu_boardobjgrp *)pboardobjgrppmu,
418 &pboardobjpmustatus, index);
419 if (status) {
420 nvgpu_err(g, "could not get status object instance");
421 return status;
422 }
423
424 status = clk_vf_point_update(g, pboardobj,
425 (struct nv_pmu_boardobj *)pboardobjpmustatus);
426 if (status) {
427 nvgpu_err(g, "invalid data from pmu at %d", index);
428 return status;
429 }
430 }
431
432 return 0;
433}
diff --git a/include/clk/clk_vf_point.h b/include/clk/clk_vf_point.h
new file mode 100644
index 0000000..b72fe64
--- /dev/null
+++ b/include/clk/clk_vf_point.h
@@ -0,0 +1,83 @@
1/*
2* Copyright (c) 2016-2018, 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 NVGPU_CLK_VF_POINT_H
24#define NVGPU_CLK_VF_POINT_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
31int clk_vf_point_sw_setup(struct gk20a *g);
32int clk_vf_point_pmu_setup(struct gk20a *g);
33int 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 struct ctrl_clk_freq_delta freq_delta;
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 /* NVGPU_CLK_VF_POINT_H */
diff --git a/include/clk/clk_vin.c b/include/clk/clk_vin.c
new file mode 100644
index 0000000..e0a4a5b
--- /dev/null
+++ b/include/clk/clk_vin.c
@@ -0,0 +1,573 @@
1/*
2 * Copyright (c) 2016-2018, 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#include <nvgpu/io.h>
26#include <nvgpu/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
38static int devinit_get_vin_device_table(struct gk20a *g,
39 struct avfsvinobjs *pvinobjs);
40
41static int vin_device_construct_v10(struct gk20a *g,
42 struct boardobj **ppboardobj,
43 u16 size, void *pargs);
44static int vin_device_construct_v20(struct gk20a *g,
45 struct boardobj **ppboardobj,
46 u16 size, void *pargs);
47static int vin_device_construct_super(struct gk20a *g,
48 struct boardobj **ppboardobj,
49 u16 size, void *pargs);
50static struct vin_device *construct_vin_device(struct gk20a *g, void *pargs);
51
52static int vin_device_init_pmudata_v10(struct gk20a *g,
53 struct boardobj *board_obj_ptr,
54 struct nv_pmu_boardobj *ppmudata);
55static int vin_device_init_pmudata_v20(struct gk20a *g,
56 struct boardobj *board_obj_ptr,
57 struct nv_pmu_boardobj *ppmudata);
58static int vin_device_init_pmudata_super(struct gk20a *g,
59 struct boardobj *board_obj_ptr,
60 struct nv_pmu_boardobj *ppmudata);
61
62u32 clk_avfs_get_vin_cal_fuse_v10(struct gk20a *g,
63 struct avfsvinobjs *pvinobjs,
64 struct vin_device_v20 *pvindev)
65{
66 u32 status = 0;
67 u32 slope, intercept;
68 u8 i;
69
70 if (pvinobjs->calibration_rev_vbios == g->ops.fuse.read_vin_cal_fuse_rev(g)) {
71 BOARDOBJGRP_FOR_EACH(&(pvinobjs->super.super),
72 struct vin_device_v20 *, pvindev, i) {
73 slope = 0;
74 intercept = 0;
75 pvindev = (struct vin_device_v20 *)CLK_GET_VIN_DEVICE(pvinobjs, i);
76 status = g->ops.fuse.read_vin_cal_slope_intercept_fuse(g,
77 pvindev->super.id, &slope, &intercept);
78 if (status) {
79 nvgpu_err(g,
80 "err reading vin cal for id %x", pvindev->super.id);
81 return status;
82 }
83 pvindev->data.vin_cal.cal_v10.slope = slope;
84 pvindev->data.vin_cal.cal_v10.intercept = intercept;
85 }
86 }
87 return status;
88
89}
90
91u32 clk_avfs_get_vin_cal_fuse_v20(struct gk20a *g,
92 struct avfsvinobjs *pvinobjs,
93 struct vin_device_v20 *pvindev)
94{
95 u32 status = 0;
96 s8 gain, offset;
97 u8 i;
98
99 if (pvinobjs->calibration_rev_vbios == g->ops.fuse.read_vin_cal_fuse_rev(g)) {
100 BOARDOBJGRP_FOR_EACH(&(pvinobjs->super.super),
101 struct vin_device_v20 *, pvindev, i) {
102 gain = '\0';
103 offset = '\0';
104 pvindev = (struct vin_device_v20 *)CLK_GET_VIN_DEVICE(pvinobjs, i);
105 status = g->ops.fuse.read_vin_cal_gain_offset_fuse(g,
106 pvindev->super.id, &gain, &offset);
107 if (status) {
108 nvgpu_err(g,
109 "err reading vin cal for id %x", pvindev->super.id);
110 return status;
111 }
112 pvindev->data.vin_cal.cal_v20.gain = gain;
113 pvindev->data.vin_cal.cal_v20.offset = offset;
114 }
115 }
116 return status;
117
118}
119
120static int _clk_vin_devgrp_pmudatainit_super(struct gk20a *g,
121 struct boardobjgrp *pboardobjgrp,
122 struct nv_pmu_boardobjgrp_super *pboardobjgrppmu)
123{
124 struct nv_pmu_clk_clk_vin_device_boardobjgrp_set_header *pset =
125 (struct nv_pmu_clk_clk_vin_device_boardobjgrp_set_header *)
126 pboardobjgrppmu;
127 struct avfsvinobjs *pvin_obbj = (struct avfsvinobjs *)pboardobjgrp;
128 int status = 0;
129
130 nvgpu_log_info(g, " ");
131
132 status = boardobjgrp_pmudatainit_e32(g, pboardobjgrp, pboardobjgrppmu);
133
134 pset->b_vin_is_disable_allowed = pvin_obbj->vin_is_disable_allowed;
135
136 nvgpu_log_info(g, " Done");
137 return status;
138}
139
140static int _clk_vin_devgrp_pmudata_instget(struct gk20a *g,
141 struct nv_pmu_boardobjgrp *pmuboardobjgrp,
142 struct nv_pmu_boardobj **ppboardobjpmudata,
143 u8 idx)
144{
145 struct nv_pmu_clk_clk_vin_device_boardobj_grp_set *pgrp_set =
146 (struct nv_pmu_clk_clk_vin_device_boardobj_grp_set *)
147 pmuboardobjgrp;
148
149 nvgpu_log_info(g, " ");
150
151 /*check whether pmuboardobjgrp has a valid boardobj in index*/
152 if (((u32)BIT(idx) &
153 pgrp_set->hdr.data.super.obj_mask.super.data[0]) == 0) {
154 return -EINVAL;
155 }
156
157 *ppboardobjpmudata = (struct nv_pmu_boardobj *)
158 &pgrp_set->objects[idx].data.board_obj;
159 nvgpu_log_info(g, " Done");
160 return 0;
161}
162
163static int _clk_vin_devgrp_pmustatus_instget(struct gk20a *g,
164 void *pboardobjgrppmu,
165 struct nv_pmu_boardobj_query **ppboardobjpmustatus,
166 u8 idx)
167{
168 struct nv_pmu_clk_clk_vin_device_boardobj_grp_get_status *pgrp_get_status =
169 (struct nv_pmu_clk_clk_vin_device_boardobj_grp_get_status *)
170 pboardobjgrppmu;
171
172 /*check whether pmuboardobjgrp has a valid boardobj in index*/
173 if (((u32)BIT(idx) &
174 pgrp_get_status->hdr.data.super.obj_mask.super.data[0]) == 0) {
175 return -EINVAL;
176 }
177
178 *ppboardobjpmustatus = (struct nv_pmu_boardobj_query *)
179 &pgrp_get_status->objects[idx].data.board_obj;
180 return 0;
181}
182
183int clk_vin_sw_setup(struct gk20a *g)
184{
185 int status;
186 struct boardobjgrp *pboardobjgrp = NULL;
187 struct vin_device_v20 *pvindev = NULL;
188 struct avfsvinobjs *pvinobjs;
189
190 nvgpu_log_info(g, " ");
191
192 status = boardobjgrpconstruct_e32(g, &g->clk_pmu.avfs_vinobjs.super);
193 if (status) {
194 nvgpu_err(g,
195 "error creating boardobjgrp for clk vin, statu - 0x%x",
196 status);
197 goto done;
198 }
199
200 pboardobjgrp = &g->clk_pmu.avfs_vinobjs.super.super;
201 pvinobjs = &g->clk_pmu.avfs_vinobjs;
202
203 BOARDOBJGRP_PMU_CONSTRUCT(pboardobjgrp, CLK, VIN_DEVICE);
204
205 status = BOARDOBJGRP_PMU_CMD_GRP_SET_CONSTRUCT(g, pboardobjgrp,
206 clk, CLK, clk_vin_device, CLK_VIN_DEVICE);
207 if (status) {
208 nvgpu_err(g,
209 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
210 status);
211 goto done;
212 }
213
214 pboardobjgrp->pmudatainit = _clk_vin_devgrp_pmudatainit_super;
215 pboardobjgrp->pmudatainstget = _clk_vin_devgrp_pmudata_instget;
216 pboardobjgrp->pmustatusinstget = _clk_vin_devgrp_pmustatus_instget;
217
218 status = devinit_get_vin_device_table(g, &g->clk_pmu.avfs_vinobjs);
219 if (status) {
220 goto done;
221 }
222
223 /*update vin calibration to fuse */
224 g->ops.pmu_ver.clk.clk_avfs_get_vin_cal_data(g, pvinobjs, pvindev);
225
226 status = BOARDOBJGRP_PMU_CMD_GRP_GET_STATUS_CONSTRUCT(g,
227 &g->clk_pmu.avfs_vinobjs.super.super,
228 clk, CLK, clk_vin_device, CLK_VIN_DEVICE);
229 if (status) {
230 nvgpu_err(g,
231 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
232 status);
233 goto done;
234 }
235
236done:
237 nvgpu_log_info(g, " done status %x", status);
238 return status;
239}
240
241int clk_vin_pmu_setup(struct gk20a *g)
242{
243 int status;
244 struct boardobjgrp *pboardobjgrp = NULL;
245
246 nvgpu_log_info(g, " ");
247
248 pboardobjgrp = &g->clk_pmu.avfs_vinobjs.super.super;
249
250 if (!pboardobjgrp->bconstructed) {
251 return -EINVAL;
252 }
253
254 status = pboardobjgrp->pmuinithandle(g, pboardobjgrp);
255
256 nvgpu_log_info(g, "Done");
257 return status;
258}
259
260static int devinit_get_vin_device_table(struct gk20a *g,
261 struct avfsvinobjs *pvinobjs)
262{
263 int status = 0;
264 u8 *vin_table_ptr = NULL;
265 struct vin_descriptor_header_10 vin_desc_table_header = { 0 };
266 struct vin_descriptor_entry_10 vin_desc_table_entry = { 0 };
267 u8 *vin_tbl_entry_ptr = NULL;
268 u32 index = 0;
269 u32 slope=0, intercept=0;
270 s8 offset='\0', gain='\0';
271 struct vin_device *pvin_dev;
272 u32 cal_type;
273
274 union {
275 struct boardobj boardobj;
276 struct vin_device vin_device;
277 struct vin_device_v10 vin_device_v10;
278 struct vin_device_v20 vin_device_v20;
279 } vin_device_data;
280
281 nvgpu_log_info(g, " ");
282
283 vin_table_ptr = (u8 *)nvgpu_bios_get_perf_table_ptrs(g,
284 g->bios.clock_token, VIN_TABLE);
285 if (vin_table_ptr == NULL) {
286 status = -1;
287 goto done;
288 }
289
290 memcpy(&vin_desc_table_header, vin_table_ptr,
291 sizeof(struct vin_descriptor_header_10));
292
293 pvinobjs->calibration_rev_vbios =
294 BIOS_GET_FIELD(vin_desc_table_header.flags0,
295 NV_VIN_DESC_FLAGS0_VIN_CAL_REVISION);
296 pvinobjs->vin_is_disable_allowed =
297 BIOS_GET_FIELD(vin_desc_table_header.flags0,
298 NV_VIN_DESC_FLAGS0_DISABLE_CONTROL);
299 cal_type = BIOS_GET_FIELD(vin_desc_table_header.flags0,
300 NV_VIN_DESC_FLAGS0_VIN_CAL_TYPE);
301 if (!cal_type) {
302 cal_type = CTRL_CLK_VIN_CAL_TYPE_V10;
303 }
304
305 switch (cal_type) {
306 case CTRL_CLK_VIN_CAL_TYPE_V10:
307 /* VIN calibration slope: XX.YYY mV/code => XXYYY uV/code*/
308 slope = ((BIOS_GET_FIELD(vin_desc_table_header.vin_cal,
309 NV_VIN_DESC_VIN_CAL_SLOPE_INTEGER) * 1000)) +
310 ((BIOS_GET_FIELD(vin_desc_table_header.vin_cal,
311 NV_VIN_DESC_VIN_CAL_SLOPE_FRACTION)));
312
313 /* VIN calibration intercept: ZZZ.W mV => ZZZW00 uV */
314 intercept = ((BIOS_GET_FIELD(vin_desc_table_header.vin_cal,
315 NV_VIN_DESC_VIN_CAL_INTERCEPT_INTEGER) * 1000)) +
316 ((BIOS_GET_FIELD(vin_desc_table_header.vin_cal,
317 NV_VIN_DESC_VIN_CAL_INTERCEPT_FRACTION) * 100));
318
319 break;
320 case CTRL_CLK_VIN_CAL_TYPE_V20:
321 offset = BIOS_GET_FIELD(vin_desc_table_header.vin_cal,
322 NV_VIN_DESC_VIN_CAL_OFFSET);
323 gain = BIOS_GET_FIELD(vin_desc_table_header.vin_cal,
324 NV_VIN_DESC_VIN_CAL_GAIN);
325 break;
326 default:
327 status = -1;
328 goto done;
329 }
330 /* Read table entries*/
331 vin_tbl_entry_ptr = vin_table_ptr + vin_desc_table_header.header_sizee;
332 for (index = 0; index < vin_desc_table_header.entry_count; index++) {
333 memcpy(&vin_desc_table_entry, vin_tbl_entry_ptr,
334 sizeof(struct vin_descriptor_entry_10));
335
336 if (vin_desc_table_entry.vin_device_type == CTRL_CLK_VIN_TYPE_DISABLED) {
337 continue;
338 }
339
340 vin_device_data.boardobj.type =
341 (u8)vin_desc_table_entry.vin_device_type;
342 vin_device_data.vin_device.id = (u8)vin_desc_table_entry.vin_device_id;
343 vin_device_data.vin_device.volt_domain_vbios =
344 (u8)vin_desc_table_entry.volt_domain_vbios;
345 vin_device_data.vin_device.flls_shared_mask = 0;
346
347 switch (vin_device_data.boardobj.type) {
348 case CTRL_CLK_VIN_TYPE_V10:
349 vin_device_data.vin_device_v10.data.vin_cal.slope = slope;
350 vin_device_data.vin_device_v10.data.vin_cal.intercept = intercept;
351 break;
352 case CTRL_CLK_VIN_TYPE_V20:
353 vin_device_data.vin_device_v20.data.cal_type = (u8) cal_type;
354 vin_device_data.vin_device_v20.data.vin_cal.cal_v20.offset = offset;
355 vin_device_data.vin_device_v20.data.vin_cal.cal_v20.gain = gain;
356 break;
357 default:
358 status = -1;
359 goto done;
360 };
361
362 pvin_dev = construct_vin_device(g, (void *)&vin_device_data);
363
364 status = boardobjgrp_objinsert(&pvinobjs->super.super,
365 (struct boardobj *)pvin_dev, index);
366
367 vin_tbl_entry_ptr += vin_desc_table_header.entry_size;
368 }
369
370done:
371 nvgpu_log_info(g, " done status %x", status);
372 return status;
373}
374
375static int vin_device_construct_v10(struct gk20a *g,
376 struct boardobj **ppboardobj,
377 u16 size, void *pargs)
378{
379 struct boardobj *ptmpobj = (struct boardobj *)pargs;
380 struct vin_device_v10 *pvin_device_v10;
381 struct vin_device_v10 *ptmpvin_device_v10 = (struct vin_device_v10 *)pargs;
382 int status = 0;
383
384 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_CLK_VIN_TYPE_V10) {
385 return -EINVAL;
386 }
387
388 ptmpobj->type_mask |= BIT(CTRL_CLK_VIN_TYPE_V10);
389 status = vin_device_construct_super(g, ppboardobj, size, pargs);
390 if (status) {
391 return -EINVAL;
392 }
393
394 pvin_device_v10 = (struct vin_device_v10 *)*ppboardobj;
395
396 pvin_device_v10->super.super.pmudatainit =
397 vin_device_init_pmudata_v10;
398
399 pvin_device_v10->data.vin_cal.slope = ptmpvin_device_v10->data.vin_cal.slope;
400 pvin_device_v10->data.vin_cal.intercept = ptmpvin_device_v10->data.vin_cal.intercept;
401
402 return status;
403}
404
405static int vin_device_construct_v20(struct gk20a *g,
406 struct boardobj **ppboardobj,
407 u16 size, void *pargs)
408{
409 struct boardobj *ptmpobj = (struct boardobj *)pargs;
410 struct vin_device_v20 *pvin_device_v20;
411 struct vin_device_v20 *ptmpvin_device_v20 = (struct vin_device_v20 *)pargs;
412 int status = 0;
413
414 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_CLK_VIN_TYPE_V20) {
415 return -EINVAL;
416 }
417
418 ptmpobj->type_mask |= BIT(CTRL_CLK_VIN_TYPE_V20);
419 status = vin_device_construct_super(g, ppboardobj, size, pargs);
420 if (status) {
421 return -EINVAL;
422 }
423
424 pvin_device_v20 = (struct vin_device_v20 *)*ppboardobj;
425
426 pvin_device_v20->super.super.pmudatainit =
427 vin_device_init_pmudata_v20;
428
429 pvin_device_v20->data.cal_type = ptmpvin_device_v20->data.cal_type;
430 pvin_device_v20->data.vin_cal.cal_v20.offset = ptmpvin_device_v20->data.vin_cal.cal_v20.offset;
431 pvin_device_v20->data.vin_cal.cal_v20.gain = ptmpvin_device_v20->data.vin_cal.cal_v20.gain;
432
433 return status;
434}
435static int vin_device_construct_super(struct gk20a *g,
436 struct boardobj **ppboardobj,
437 u16 size, void *pargs)
438{
439 struct vin_device *pvin_device;
440 struct vin_device *ptmpvin_device = (struct vin_device *)pargs;
441 int status = 0;
442 status = boardobj_construct_super(g, ppboardobj, size, pargs);
443
444 if (status) {
445 return -EINVAL;
446 }
447
448 pvin_device = (struct vin_device *)*ppboardobj;
449
450 pvin_device->super.pmudatainit =
451 vin_device_init_pmudata_super;
452
453 pvin_device->id = ptmpvin_device->id;
454 pvin_device->volt_domain_vbios = ptmpvin_device->volt_domain_vbios;
455 pvin_device->flls_shared_mask = ptmpvin_device->flls_shared_mask;
456 pvin_device->volt_domain = CTRL_VOLT_DOMAIN_LOGIC;
457
458 return status;
459}
460static struct vin_device *construct_vin_device(struct gk20a *g, void *pargs)
461{
462 struct boardobj *board_obj_ptr = NULL;
463 int status;
464
465 nvgpu_log_info(g, " %d", BOARDOBJ_GET_TYPE(pargs));
466 switch (BOARDOBJ_GET_TYPE(pargs)) {
467 case CTRL_CLK_VIN_TYPE_V10:
468 status = vin_device_construct_v10(g, &board_obj_ptr,
469 sizeof(struct vin_device_v10), pargs);
470 break;
471
472 case CTRL_CLK_VIN_TYPE_V20:
473 status = vin_device_construct_v20(g, &board_obj_ptr,
474 sizeof(struct vin_device_v20), pargs);
475 break;
476
477 default:
478 return NULL;
479 };
480
481 if (status) {
482 return NULL;
483 }
484
485 nvgpu_log_info(g, " Done");
486
487 return (struct vin_device *)board_obj_ptr;
488}
489
490
491
492static int vin_device_init_pmudata_v10(struct gk20a *g,
493 struct boardobj *board_obj_ptr,
494 struct nv_pmu_boardobj *ppmudata)
495{
496 int status = 0;
497 struct vin_device_v20 *pvin_dev_v20;
498 struct nv_pmu_clk_clk_vin_device_v10_boardobj_set *perf_pmu_data;
499
500 nvgpu_log_info(g, " ");
501
502 status = vin_device_init_pmudata_super(g, board_obj_ptr, ppmudata);
503 if (status != 0) {
504 return status;
505 }
506
507 pvin_dev_v20 = (struct vin_device_v20 *)board_obj_ptr;
508 perf_pmu_data = (struct nv_pmu_clk_clk_vin_device_v10_boardobj_set *)
509 ppmudata;
510
511 perf_pmu_data->data.vin_cal.intercept = pvin_dev_v20->data.vin_cal.cal_v10.intercept;
512 perf_pmu_data->data.vin_cal.slope = pvin_dev_v20->data.vin_cal.cal_v10.slope;
513
514 nvgpu_log_info(g, " Done");
515
516 return status;
517}
518
519static int vin_device_init_pmudata_v20(struct gk20a *g,
520 struct boardobj *board_obj_ptr,
521 struct nv_pmu_boardobj *ppmudata)
522{
523 int status = 0;
524 struct vin_device_v20 *pvin_dev_v20;
525 struct nv_pmu_clk_clk_vin_device_v20_boardobj_set *perf_pmu_data;
526
527 nvgpu_log_info(g, " ");
528
529 status = vin_device_init_pmudata_super(g, board_obj_ptr, ppmudata);
530 if (status != 0) {
531 return status;
532 }
533
534 pvin_dev_v20 = (struct vin_device_v20 *)board_obj_ptr;
535 perf_pmu_data = (struct nv_pmu_clk_clk_vin_device_v20_boardobj_set *)
536 ppmudata;
537
538 perf_pmu_data->data.cal_type = pvin_dev_v20->data.cal_type;
539 perf_pmu_data->data.vin_cal.cal_v20.offset = pvin_dev_v20->data.vin_cal.cal_v20.offset;
540 perf_pmu_data->data.vin_cal.cal_v20.gain = pvin_dev_v20->data.vin_cal.cal_v20.gain;
541
542 nvgpu_log_info(g, " Done");
543
544 return status;
545}
546
547static int vin_device_init_pmudata_super(struct gk20a *g,
548 struct boardobj *board_obj_ptr,
549 struct nv_pmu_boardobj *ppmudata)
550{
551 int status = 0;
552 struct vin_device *pvin_dev;
553 struct nv_pmu_clk_clk_vin_device_boardobj_set *perf_pmu_data;
554
555 nvgpu_log_info(g, " ");
556
557 status = boardobj_pmudatainit_super(g, board_obj_ptr, ppmudata);
558 if (status != 0) {
559 return status;
560 }
561
562 pvin_dev = (struct vin_device *)board_obj_ptr;
563 perf_pmu_data = (struct nv_pmu_clk_clk_vin_device_boardobj_set *)
564 ppmudata;
565
566 perf_pmu_data->id = pvin_dev->id;
567 perf_pmu_data->volt_domain = pvin_dev->volt_domain;
568 perf_pmu_data->flls_shared_mask = pvin_dev->flls_shared_mask;
569
570 nvgpu_log_info(g, " Done");
571
572 return status;
573}
diff --git a/include/clk/clk_vin.h b/include/clk/clk_vin.h
new file mode 100644
index 0000000..73b93e4
--- /dev/null
+++ b/include/clk/clk_vin.h
@@ -0,0 +1,79 @@
1/*
2* Copyright (c) 2016-2018, 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 NVGPU_CLK_VIN_H
24#define NVGPU_CLK_VIN_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 flls_shared_mask;
48
49 vin_device_state_load *state_load;
50};
51
52struct vin_device_v10 {
53 struct vin_device super;
54 struct ctrl_clk_vin_device_info_data_v10 data;
55};
56
57struct vin_device_v20 {
58 struct vin_device super;
59 struct ctrl_clk_vin_device_info_data_v20 data;
60};
61
62/* get vin device object from descriptor table index*/
63#define CLK_GET_VIN_DEVICE(pvinobjs, dev_index) \
64 ((struct vin_device *)BOARDOBJGRP_OBJ_GET_BY_IDX( \
65 ((struct boardobjgrp *)&(pvinobjs->super.super)), (dev_index)))
66
67boardobj_construct construct_vindevice;
68boardobj_pmudatainit vindeviceinit_pmudata_super;
69
70int clk_vin_sw_setup(struct gk20a *g);
71int clk_vin_pmu_setup(struct gk20a *g);
72u32 clk_avfs_get_vin_cal_fuse_v10(struct gk20a *g,
73 struct avfsvinobjs *pvinobjs,
74 struct vin_device_v20 *pvindev);
75u32 clk_avfs_get_vin_cal_fuse_v20(struct gk20a *g,
76 struct avfsvinobjs *pvinobjs,
77 struct vin_device_v20 *pvindev);
78
79#endif /* NVGPU_CLK_VIN_H */