summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/clk
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/nvgpu/clk')
-rw-r--r--drivers/gpu/nvgpu/clk/clk.c529
-rw-r--r--drivers/gpu/nvgpu/clk/clk.h120
-rw-r--r--drivers/gpu/nvgpu/clk/clk_arb.c1548
-rw-r--r--drivers/gpu/nvgpu/clk/clk_arb.h71
-rw-r--r--drivers/gpu/nvgpu/clk/clk_domain.c1113
-rw-r--r--drivers/gpu/nvgpu/clk/clk_domain.h116
-rw-r--r--drivers/gpu/nvgpu/clk/clk_fll.c440
-rw-r--r--drivers/gpu/nvgpu/clk/clk_fll.h68
-rw-r--r--drivers/gpu/nvgpu/clk/clk_freq_controller.c454
-rw-r--r--drivers/gpu/nvgpu/clk/clk_freq_controller.h74
-rw-r--r--drivers/gpu/nvgpu/clk/clk_mclk.c2499
-rw-r--r--drivers/gpu/nvgpu/clk/clk_mclk.h52
-rw-r--r--drivers/gpu/nvgpu/clk/clk_prog.c1098
-rw-r--r--drivers/gpu/nvgpu/clk/clk_prog.h90
-rw-r--r--drivers/gpu/nvgpu/clk/clk_vf_point.c418
-rw-r--r--drivers/gpu/nvgpu/clk/clk_vf_point.h74
-rw-r--r--drivers/gpu/nvgpu/clk/clk_vin.c466
-rw-r--r--drivers/gpu/nvgpu/clk/clk_vin.h56
18 files changed, 9286 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/clk/clk.c b/drivers/gpu/nvgpu/clk/clk.c
new file mode 100644
index 00000000..ecd53c02
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk.c
@@ -0,0 +1,529 @@
1/*
2 * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 */
13
14#include "gk20a/gk20a.h"
15#include "clk.h"
16#include "pmuif/gpmuifclk.h"
17#include "pmuif/gpmuifvolt.h"
18#include "ctrl/ctrlclk.h"
19#include "ctrl/ctrlvolt.h"
20#include "volt/volt.h"
21#include "gk20a/pmu_gk20a.h"
22
23#define BOOT_GPC2CLK_MHZ 2581
24#define BOOT_MCLK_MHZ 3003
25
26struct clkrpc_pmucmdhandler_params {
27 struct nv_pmu_clk_rpc *prpccall;
28 u32 success;
29};
30
31static void clkrpc_pmucmdhandler(struct gk20a *g, struct pmu_msg *msg,
32 void *param, u32 handle, u32 status)
33{
34 struct clkrpc_pmucmdhandler_params *phandlerparams =
35 (struct clkrpc_pmucmdhandler_params *)param;
36
37 gk20a_dbg_info("");
38
39 if (msg->msg.clk.msg_type != NV_PMU_CLK_MSG_ID_RPC) {
40 gk20a_err(dev_from_gk20a(g),
41 "unsupported msg for VFE LOAD RPC %x",
42 msg->msg.clk.msg_type);
43 return;
44 }
45
46 if (phandlerparams->prpccall->b_supported)
47 phandlerparams->success = 1;
48}
49
50int clk_pmu_freq_controller_load(struct gk20a *g, bool bload)
51{
52 struct pmu_cmd cmd;
53 struct pmu_msg msg;
54 struct pmu_payload payload = { {0} };
55 u32 status;
56 u32 seqdesc;
57 struct nv_pmu_clk_rpc rpccall = {0};
58 struct clkrpc_pmucmdhandler_params handler = {0};
59 struct nv_pmu_clk_load *clkload;
60 struct clk_freq_controllers *pclk_freq_controllers;
61 struct ctrl_boardobjgrp_mask_e32 *load_mask;
62
63 pclk_freq_controllers = &g->clk_pmu.clk_freq_controllers;
64 rpccall.function = NV_PMU_CLK_RPC_ID_LOAD;
65 clkload = &rpccall.params.clk_load;
66 clkload->feature = NV_NV_PMU_CLK_LOAD_FEATURE_FREQ_CONTROLLER;
67 clkload->action_mask = bload ?
68 NV_NV_PMU_CLK_LOAD_ACTION_MASK_FREQ_CONTROLLER_CALLBACK_YES :
69 NV_NV_PMU_CLK_LOAD_ACTION_MASK_FREQ_CONTROLLER_CALLBACK_NO;
70
71 load_mask = &rpccall.params.clk_load.payload.freq_controllers.load_mask;
72
73 status = boardobjgrpmask_export(
74 &pclk_freq_controllers->freq_ctrl_load_mask.super,
75 pclk_freq_controllers->freq_ctrl_load_mask.super.bitcount,
76 &load_mask->super);
77
78 cmd.hdr.unit_id = PMU_UNIT_CLK;
79 cmd.hdr.size = (u32)sizeof(struct nv_pmu_clk_cmd) +
80 (u32)sizeof(struct pmu_hdr);
81
82 cmd.cmd.clk.cmd_type = NV_PMU_CLK_CMD_ID_RPC;
83 msg.hdr.size = sizeof(struct pmu_msg);
84
85 payload.in.buf = (u8 *)&rpccall;
86 payload.in.size = (u32)sizeof(struct nv_pmu_clk_rpc);
87 payload.in.fb_size = PMU_CMD_SUBMIT_PAYLOAD_PARAMS_FB_SIZE_UNUSED;
88 payload.in.offset = NV_PMU_CLK_CMD_RPC_ALLOC_OFFSET;
89
90 payload.out.buf = (u8 *)&rpccall;
91 payload.out.size = (u32)sizeof(struct nv_pmu_clk_rpc);
92 payload.out.fb_size = PMU_CMD_SUBMIT_PAYLOAD_PARAMS_FB_SIZE_UNUSED;
93 payload.out.offset = NV_PMU_CLK_MSG_RPC_ALLOC_OFFSET;
94
95 handler.prpccall = &rpccall;
96 handler.success = 0;
97 status = gk20a_pmu_cmd_post(g, &cmd, NULL, &payload,
98 PMU_COMMAND_QUEUE_LPQ,
99 clkrpc_pmucmdhandler, (void *)&handler,
100 &seqdesc, ~0);
101
102 if (status) {
103 gk20a_err(dev_from_gk20a(g),
104 "unable to post clk RPC cmd %x",
105 cmd.cmd.clk.cmd_type);
106 goto done;
107 }
108
109 pmu_wait_message_cond(&g->pmu,
110 gk20a_get_gr_idle_timeout(g),
111 &handler.success, 1);
112
113 if (handler.success == 0) {
114 gk20a_err(dev_from_gk20a(g), "rpc call to load freq cntlr cal failed");
115 status = -EINVAL;
116 }
117
118done:
119 return status;
120}
121
122u32 clk_pmu_vin_load(struct gk20a *g)
123{
124 struct pmu_cmd cmd;
125 struct pmu_msg msg;
126 struct pmu_payload payload = { {0} };
127 u32 status;
128 u32 seqdesc;
129 struct nv_pmu_clk_rpc rpccall = {0};
130 struct clkrpc_pmucmdhandler_params handler = {0};
131 struct nv_pmu_clk_load *clkload;
132
133 rpccall.function = NV_PMU_CLK_RPC_ID_LOAD;
134 clkload = &rpccall.params.clk_load;
135 clkload->feature = NV_NV_PMU_CLK_LOAD_FEATURE_VIN;
136 clkload->action_mask = NV_NV_PMU_CLK_LOAD_ACTION_MASK_VIN_HW_CAL_PROGRAM_YES << 4;
137
138 cmd.hdr.unit_id = PMU_UNIT_CLK;
139 cmd.hdr.size = (u32)sizeof(struct nv_pmu_clk_cmd) +
140 (u32)sizeof(struct pmu_hdr);
141
142 cmd.cmd.clk.cmd_type = NV_PMU_CLK_CMD_ID_RPC;
143 msg.hdr.size = sizeof(struct pmu_msg);
144
145 payload.in.buf = (u8 *)&rpccall;
146 payload.in.size = (u32)sizeof(struct nv_pmu_clk_rpc);
147 payload.in.fb_size = PMU_CMD_SUBMIT_PAYLOAD_PARAMS_FB_SIZE_UNUSED;
148 payload.in.offset = NV_PMU_CLK_CMD_RPC_ALLOC_OFFSET;
149
150 payload.out.buf = (u8 *)&rpccall;
151 payload.out.size = (u32)sizeof(struct nv_pmu_clk_rpc);
152 payload.out.fb_size = PMU_CMD_SUBMIT_PAYLOAD_PARAMS_FB_SIZE_UNUSED;
153 payload.out.offset = NV_PMU_CLK_MSG_RPC_ALLOC_OFFSET;
154
155 handler.prpccall = &rpccall;
156 handler.success = 0;
157 status = gk20a_pmu_cmd_post(g, &cmd, NULL, &payload,
158 PMU_COMMAND_QUEUE_LPQ,
159 clkrpc_pmucmdhandler, (void *)&handler,
160 &seqdesc, ~0);
161
162 if (status) {
163 gk20a_err(dev_from_gk20a(g),
164 "unable to post clk RPC cmd %x",
165 cmd.cmd.clk.cmd_type);
166 goto done;
167 }
168
169 pmu_wait_message_cond(&g->pmu,
170 gk20a_get_gr_idle_timeout(g),
171 &handler.success, 1);
172
173 if (handler.success == 0) {
174 gk20a_err(dev_from_gk20a(g), "rpc call to load vin cal failed");
175 status = -EINVAL;
176 }
177
178done:
179 return status;
180}
181
182static u32 clk_pmu_vf_inject(struct gk20a *g, struct set_fll_clk *setfllclk)
183{
184 struct pmu_cmd cmd;
185 struct pmu_msg msg;
186 struct pmu_payload payload = { {0} };
187 u32 status;
188 u32 seqdesc;
189 struct nv_pmu_clk_rpc rpccall = {0};
190 struct clkrpc_pmucmdhandler_params handler = {0};
191 struct nv_pmu_clk_vf_change_inject *vfchange;
192
193 if ((setfllclk->gpc2clkmhz == 0) || (setfllclk->xbar2clkmhz == 0) ||
194 (setfllclk->sys2clkmhz == 0) || (setfllclk->voltuv == 0))
195 return -EINVAL;
196
197 if ((setfllclk->target_regime_id_gpc > CTRL_CLK_FLL_REGIME_ID_FR) ||
198 (setfllclk->target_regime_id_sys > CTRL_CLK_FLL_REGIME_ID_FR) ||
199 (setfllclk->target_regime_id_xbar > CTRL_CLK_FLL_REGIME_ID_FR))
200 return -EINVAL;
201
202 rpccall.function = NV_PMU_CLK_RPC_ID_CLK_VF_CHANGE_INJECT;
203 vfchange = &rpccall.params.clk_vf_change_inject;
204 vfchange->flags = 0;
205 vfchange->clk_list.num_domains = 3;
206 vfchange->clk_list.clk_domains[0].clk_domain = CTRL_CLK_DOMAIN_GPC2CLK;
207 vfchange->clk_list.clk_domains[0].clk_freq_khz =
208 setfllclk->gpc2clkmhz * 1000;
209 vfchange->clk_list.clk_domains[0].clk_flags = 0;
210 vfchange->clk_list.clk_domains[0].current_regime_id =
211 setfllclk->current_regime_id_gpc;
212 vfchange->clk_list.clk_domains[0].target_regime_id =
213 setfllclk->target_regime_id_gpc;
214 vfchange->clk_list.clk_domains[1].clk_domain = CTRL_CLK_DOMAIN_XBAR2CLK;
215 vfchange->clk_list.clk_domains[1].clk_freq_khz =
216 setfllclk->xbar2clkmhz * 1000;
217 vfchange->clk_list.clk_domains[1].clk_flags = 0;
218 vfchange->clk_list.clk_domains[1].current_regime_id =
219 setfllclk->current_regime_id_xbar;
220 vfchange->clk_list.clk_domains[1].target_regime_id =
221 setfllclk->target_regime_id_xbar;
222 vfchange->clk_list.clk_domains[2].clk_domain = CTRL_CLK_DOMAIN_SYS2CLK;
223 vfchange->clk_list.clk_domains[2].clk_freq_khz =
224 setfllclk->sys2clkmhz * 1000;
225 vfchange->clk_list.clk_domains[2].clk_flags = 0;
226 vfchange->clk_list.clk_domains[2].current_regime_id =
227 setfllclk->current_regime_id_sys;
228 vfchange->clk_list.clk_domains[2].target_regime_id =
229 setfllclk->target_regime_id_sys;
230 vfchange->volt_list.num_rails = 1;
231 vfchange->volt_list.rails[0].volt_domain = CTRL_VOLT_DOMAIN_LOGIC;
232 vfchange->volt_list.rails[0].voltage_uv = setfllclk->voltuv;
233 vfchange->volt_list.rails[0].voltage_min_noise_unaware_uv =
234 setfllclk->voltuv;
235
236 cmd.hdr.unit_id = PMU_UNIT_CLK;
237 cmd.hdr.size = (u32)sizeof(struct nv_pmu_clk_cmd) +
238 (u32)sizeof(struct pmu_hdr);
239
240 cmd.cmd.clk.cmd_type = NV_PMU_CLK_CMD_ID_RPC;
241 msg.hdr.size = sizeof(struct pmu_msg);
242
243 payload.in.buf = (u8 *)&rpccall;
244 payload.in.size = (u32)sizeof(struct nv_pmu_clk_rpc);
245 payload.in.fb_size = PMU_CMD_SUBMIT_PAYLOAD_PARAMS_FB_SIZE_UNUSED;
246 payload.in.offset = NV_PMU_CLK_CMD_RPC_ALLOC_OFFSET;
247
248 payload.out.buf = (u8 *)&rpccall;
249 payload.out.size = (u32)sizeof(struct nv_pmu_clk_rpc);
250 payload.out.fb_size = PMU_CMD_SUBMIT_PAYLOAD_PARAMS_FB_SIZE_UNUSED;
251 payload.out.offset = NV_PMU_CLK_MSG_RPC_ALLOC_OFFSET;
252
253 handler.prpccall = &rpccall;
254 handler.success = 0;
255
256 status = gk20a_pmu_cmd_post(g, &cmd, NULL, &payload,
257 PMU_COMMAND_QUEUE_LPQ,
258 clkrpc_pmucmdhandler, (void *)&handler,
259 &seqdesc, ~0);
260
261 if (status) {
262 gk20a_err(dev_from_gk20a(g),
263 "unable to post clk RPC cmd %x",
264 cmd.cmd.clk.cmd_type);
265 goto done;
266 }
267
268 pmu_wait_message_cond(&g->pmu,
269 gk20a_get_gr_idle_timeout(g),
270 &handler.success, 1);
271
272 if (handler.success == 0) {
273 gk20a_err(dev_from_gk20a(g), "rpc call to inject clock failed");
274 status = -EINVAL;
275 }
276done:
277 return status;
278}
279
280static u32 find_regime_id(struct gk20a *g, u32 domain, u16 clkmhz)
281{
282 struct fll_device *pflldev;
283 u8 j;
284 struct clk_pmupstate *pclk = &g->clk_pmu;
285
286 BOARDOBJGRP_FOR_EACH(&(pclk->avfs_fllobjs.super.super),
287 struct fll_device *, pflldev, j) {
288 if (pflldev->clk_domain == domain) {
289 if (pflldev->regime_desc.fixed_freq_regime_limit_mhz >=
290 clkmhz)
291 return CTRL_CLK_FLL_REGIME_ID_FFR;
292 else
293 return CTRL_CLK_FLL_REGIME_ID_FR;
294 }
295 }
296 return CTRL_CLK_FLL_REGIME_ID_INVALID;
297}
298
299static int set_regime_id(struct gk20a *g, u32 domain, u32 regimeid)
300{
301 struct fll_device *pflldev;
302 u8 j;
303 struct clk_pmupstate *pclk = &g->clk_pmu;
304
305 BOARDOBJGRP_FOR_EACH(&(pclk->avfs_fllobjs.super.super),
306 struct fll_device *, pflldev, j) {
307 if (pflldev->clk_domain == domain) {
308 pflldev->regime_desc.regime_id = regimeid;
309 return 0;
310 }
311 }
312 return -EINVAL;
313}
314
315static int get_regime_id(struct gk20a *g, u32 domain, u32 *regimeid)
316{
317 struct fll_device *pflldev;
318 u8 j;
319 struct clk_pmupstate *pclk = &g->clk_pmu;
320
321 BOARDOBJGRP_FOR_EACH(&(pclk->avfs_fllobjs.super.super),
322 struct fll_device *, pflldev, j) {
323 if (pflldev->clk_domain == domain) {
324 *regimeid = pflldev->regime_desc.regime_id;
325 return 0;
326 }
327 }
328 return -EINVAL;
329}
330
331int clk_set_fll_clks(struct gk20a *g, struct set_fll_clk *setfllclk)
332{
333 int status = -EINVAL;
334
335 /*set regime ids */
336 status = get_regime_id(g, CTRL_CLK_DOMAIN_GPC2CLK,
337 &setfllclk->current_regime_id_gpc);
338 if (status)
339 goto done;
340
341 setfllclk->target_regime_id_gpc = find_regime_id(g,
342 CTRL_CLK_DOMAIN_GPC2CLK, setfllclk->gpc2clkmhz);
343
344 status = get_regime_id(g, CTRL_CLK_DOMAIN_SYS2CLK,
345 &setfllclk->current_regime_id_sys);
346 if (status)
347 goto done;
348
349 setfllclk->target_regime_id_sys = find_regime_id(g,
350 CTRL_CLK_DOMAIN_SYS2CLK, setfllclk->sys2clkmhz);
351
352 status = get_regime_id(g, CTRL_CLK_DOMAIN_XBAR2CLK,
353 &setfllclk->current_regime_id_xbar);
354 if (status)
355 goto done;
356
357 setfllclk->target_regime_id_xbar = find_regime_id(g,
358 CTRL_CLK_DOMAIN_XBAR2CLK, setfllclk->xbar2clkmhz);
359
360 status = clk_pmu_vf_inject(g, setfllclk);
361
362 if (status)
363 gk20a_err(dev_from_gk20a(g),
364 "vf inject to change clk failed");
365
366 /* save regime ids */
367 status = set_regime_id(g, CTRL_CLK_DOMAIN_XBAR2CLK,
368 setfllclk->target_regime_id_xbar);
369 if (status)
370 goto done;
371
372 status = set_regime_id(g, CTRL_CLK_DOMAIN_GPC2CLK,
373 setfllclk->target_regime_id_gpc);
374 if (status)
375 goto done;
376
377 status = set_regime_id(g, CTRL_CLK_DOMAIN_SYS2CLK,
378 setfllclk->target_regime_id_sys);
379 if (status)
380 goto done;
381done:
382 return status;
383}
384
385int clk_get_fll_clks(struct gk20a *g, struct set_fll_clk *setfllclk)
386{
387 int status = -EINVAL;
388 struct clk_domain *pdomain;
389 u8 i;
390 struct clk_pmupstate *pclk = &g->clk_pmu;
391 u16 clkmhz = 0;
392 struct clk_domain_3x_master *p3xmaster;
393 struct clk_domain_3x_slave *p3xslave;
394 unsigned long slaveidxmask;
395
396 if (setfllclk->gpc2clkmhz == 0)
397 return -EINVAL;
398
399 BOARDOBJGRP_FOR_EACH(&(pclk->clk_domainobjs.super.super),
400 struct clk_domain *, pdomain, i) {
401
402 if (pdomain->api_domain == CTRL_CLK_DOMAIN_GPC2CLK) {
403
404 if (!pdomain->super.implements(g, &pdomain->super,
405 CTRL_CLK_CLK_DOMAIN_TYPE_3X_MASTER)) {
406 status = -EINVAL;
407 goto done;
408 }
409 p3xmaster = (struct clk_domain_3x_master *)pdomain;
410 slaveidxmask = p3xmaster->slave_idxs_mask;
411 for_each_set_bit(i, &slaveidxmask, 32) {
412 p3xslave = (struct clk_domain_3x_slave *)
413 CLK_CLK_DOMAIN_GET(pclk, i);
414 if ((p3xslave->super.super.super.api_domain !=
415 CTRL_CLK_DOMAIN_XBAR2CLK) &&
416 (p3xslave->super.super.super.api_domain !=
417 CTRL_CLK_DOMAIN_SYS2CLK))
418 continue;
419 clkmhz = 0;
420 status = p3xslave->clkdomainclkgetslaveclk(g,
421 pclk,
422 (struct clk_domain *)p3xslave,
423 &clkmhz,
424 setfllclk->gpc2clkmhz);
425 if (status) {
426 status = -EINVAL;
427 goto done;
428 }
429 if (p3xslave->super.super.super.api_domain ==
430 CTRL_CLK_DOMAIN_XBAR2CLK)
431 setfllclk->xbar2clkmhz = clkmhz;
432 if (p3xslave->super.super.super.api_domain ==
433 CTRL_CLK_DOMAIN_SYS2CLK)
434 setfllclk->sys2clkmhz = clkmhz;
435 }
436 }
437 }
438done:
439 return status;
440}
441
442u32 clk_domain_print_vf_table(struct gk20a *g, u32 clkapidomain)
443{
444 u32 status = -EINVAL;
445 struct clk_domain *pdomain;
446 u8 i;
447 struct clk_pmupstate *pclk = &g->clk_pmu;
448 u16 clkmhz = 0;
449 u32 volt = 0;
450
451 BOARDOBJGRP_FOR_EACH(&(pclk->clk_domainobjs.super.super),
452 struct clk_domain *, pdomain, i) {
453 if (pdomain->api_domain == clkapidomain) {
454 status = pdomain->clkdomainclkvfsearch(g, pclk,
455 pdomain, &clkmhz, &volt,
456 CLK_PROG_VFE_ENTRY_LOGIC);
457 status = pdomain->clkdomainclkvfsearch(g, pclk,
458 pdomain, &clkmhz, &volt,
459 CLK_PROG_VFE_ENTRY_SRAM);
460 }
461 }
462 return status;
463}
464
465u32 clk_domain_get_f_or_v(
466 struct gk20a *g,
467 u32 clkapidomain,
468 u16 *pclkmhz,
469 u32 *pvoltuv,
470 u8 railidx
471)
472{
473 u32 status = -EINVAL;
474 struct clk_domain *pdomain;
475 u8 i;
476 struct clk_pmupstate *pclk = &g->clk_pmu;
477 u8 rail;
478
479 if ((pclkmhz == NULL) || (pvoltuv == NULL))
480 return -EINVAL;
481
482 if (railidx == CTRL_VOLT_DOMAIN_LOGIC)
483 rail = CLK_PROG_VFE_ENTRY_LOGIC;
484 else if (railidx == CTRL_VOLT_DOMAIN_SRAM)
485 rail = CLK_PROG_VFE_ENTRY_SRAM;
486 else
487 return -EINVAL;
488
489 BOARDOBJGRP_FOR_EACH(&(pclk->clk_domainobjs.super.super),
490 struct clk_domain *, pdomain, i) {
491 if (pdomain->api_domain == clkapidomain) {
492 status = pdomain->clkdomainclkvfsearch(g, pclk,
493 pdomain, pclkmhz, pvoltuv, rail);
494 return status;
495 }
496 }
497 return status;
498}
499
500u32 clk_domain_get_f_points(
501 struct gk20a *g,
502 u32 clkapidomain,
503 u32 *pfpointscount,
504 u16 *pfreqpointsinmhz
505)
506{
507 u32 status = -EINVAL;
508 struct clk_domain *pdomain;
509 u8 i;
510 struct clk_pmupstate *pclk = &g->clk_pmu;
511
512 if (pfpointscount == NULL)
513 return -EINVAL;
514
515 if ((pfreqpointsinmhz == NULL) && (*pfpointscount != 0))
516 return -EINVAL;
517
518 BOARDOBJGRP_FOR_EACH(&(pclk->clk_domainobjs.super.super),
519 struct clk_domain *, pdomain, i) {
520 if (pdomain->api_domain == clkapidomain) {
521 status = pdomain->clkdomainclkgetfpoints(g, pclk,
522 pdomain, pfpointscount,
523 pfreqpointsinmhz,
524 CLK_PROG_VFE_ENTRY_LOGIC);
525 return status;
526 }
527 }
528 return status;
529}
diff --git a/drivers/gpu/nvgpu/clk/clk.h b/drivers/gpu/nvgpu/clk/clk.h
new file mode 100644
index 00000000..b173a09e
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk.h
@@ -0,0 +1,120 @@
1/*
2 * general clock structures & definitions
3 *
4 * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 */
15#ifndef _CLK_H_
16#define _CLK_H_
17
18#include "clk_vin.h"
19#include "clk_fll.h"
20#include "clk_domain.h"
21#include "clk_prog.h"
22#include "clk_vf_point.h"
23#include "clk_mclk.h"
24#include "clk_freq_controller.h"
25#include "gk20a/gk20a.h"
26
27#define NV_PERF_DOMAIN_4X_CLOCK_DOMAIN_SKIP 0x10
28#define NV_PERF_DOMAIN_4X_CLOCK_DOMAIN_MASK 0x1F
29#define NV_PERF_DOMAIN_4X_CLOCK_DOMAIN_SHIFT 0
30
31/* clock related defines for GPUs supporting clock control from pmu*/
32struct clk_pmupstate {
33 struct avfsvinobjs avfs_vinobjs;
34 struct avfsfllobjs avfs_fllobjs;
35 struct clk_domains clk_domainobjs;
36 struct clk_progs clk_progobjs;
37 struct clk_vf_points clk_vf_pointobjs;
38 struct clk_mclk_state clk_mclk;
39 struct clk_freq_controllers clk_freq_controllers;
40};
41
42struct clockentry {
43 u8 vbios_clk_domain;
44 u8 clk_which;
45 u8 perf_index;
46 u32 api_clk_domain;
47};
48
49struct set_fll_clk {
50 u32 voltuv;
51 u16 gpc2clkmhz;
52 u32 current_regime_id_gpc;
53 u32 target_regime_id_gpc;
54 u16 sys2clkmhz;
55 u32 current_regime_id_sys;
56 u32 target_regime_id_sys;
57 u16 xbar2clkmhz;
58 u32 current_regime_id_xbar;
59 u32 target_regime_id_xbar;
60};
61
62#define NV_PERF_HEADER_4X_CLOCKS_DOMAINS_MAX_NUMCLKS 9
63
64struct vbios_clock_domain {
65 u8 clock_type;
66 u8 num_domains;
67 struct clockentry clock_entry[NV_PERF_HEADER_4X_CLOCKS_DOMAINS_MAX_NUMCLKS];
68};
69
70struct vbios_clocks_table_1x_hal_clock_entry {
71 enum nv_pmu_clk_clkwhich domain;
72 bool b_noise_aware_capable;
73};
74
75#define NV_PERF_HEADER_4X_CLOCKS_DOMAINS_4_GPC2CLK 0
76#define NV_PERF_HEADER_4X_CLOCKS_DOMAINS_4_XBAR2CLK 1
77#define NV_PERF_HEADER_4X_CLOCKS_DOMAINS_4_DRAMCLK 2
78#define NV_PERF_HEADER_4X_CLOCKS_DOMAINS_4_SYS2CLK 3
79#define NV_PERF_HEADER_4X_CLOCKS_DOMAINS_4_HUB2CLK 4
80#define NV_PERF_HEADER_4X_CLOCKS_DOMAINS_4_MSDCLK 5
81#define NV_PERF_HEADER_4X_CLOCKS_DOMAINS_4_PWRCLK 6
82#define NV_PERF_HEADER_4X_CLOCKS_DOMAINS_4_DISPCLK 7
83#define NV_PERF_HEADER_4X_CLOCKS_DOMAINS_4_NUMCLKS 8
84
85#define PERF_CLK_MCLK 0
86#define PERF_CLK_DISPCLK 1
87#define PERF_CLK_GPC2CLK 2
88#define PERF_CLK_HOSTCLK 3
89#define PERF_CLK_LTC2CLK 4
90#define PERF_CLK_SYS2CLK 5
91#define PERF_CLK_HUB2CLK 6
92#define PERF_CLK_LEGCLK 7
93#define PERF_CLK_MSDCLK 8
94#define PERF_CLK_XCLK 9
95#define PERF_CLK_PWRCLK 10
96#define PERF_CLK_XBAR2CLK 11
97#define PERF_CLK_PCIEGENCLK 12
98#define PERF_CLK_NUM 13
99
100#define BOOT_GPC2CLK_MHZ 2581
101
102u32 clk_pmu_vin_load(struct gk20a *g);
103u32 clk_domain_print_vf_table(struct gk20a *g, u32 clkapidomain);
104u32 clk_domain_get_f_or_v(
105 struct gk20a *g,
106 u32 clkapidomain,
107 u16 *pclkmhz,
108 u32 *pvoltuv,
109 u8 railidx
110);
111u32 clk_domain_get_f_points(
112 struct gk20a *g,
113 u32 clkapidomain,
114 u32 *fpointscount,
115 u16 *freqpointsinmhz
116);
117int clk_get_fll_clks(struct gk20a *g, struct set_fll_clk *fllclk);
118int clk_set_fll_clks(struct gk20a *g, struct set_fll_clk *fllclk);
119int clk_pmu_freq_controller_load(struct gk20a *g, bool bload);
120#endif
diff --git a/drivers/gpu/nvgpu/clk/clk_arb.c b/drivers/gpu/nvgpu/clk/clk_arb.c
new file mode 100644
index 00000000..c440dc3b
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk_arb.c
@@ -0,0 +1,1548 @@
1/*
2 * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 */
13
14#include "gk20a/gk20a.h"
15
16#include <linux/cdev.h>
17#include <linux/file.h>
18#include <linux/anon_inodes.h>
19#include <linux/nvgpu.h>
20#include <linux/bitops.h>
21#include <linux/spinlock.h>
22#include <linux/rculist.h>
23#include <linux/llist.h>
24#include "clk/clk_arb.h"
25
26
27#define MAX_F_POINTS 127
28
29#ifdef CONFIG_DEBUG_FS
30static int nvgpu_clk_arb_debugfs_init(struct gk20a *g);
31#endif
32
33static int nvgpu_clk_arb_release_event_dev(struct inode *inode,
34 struct file *filp);
35static int nvgpu_clk_arb_release_completion_dev(struct inode *inode,
36 struct file *filp);
37static unsigned int nvgpu_clk_arb_poll_dev(struct file *filp, poll_table *wait);
38
39static void nvgpu_clk_arb_run_arbiter_cb(struct work_struct *work);
40static void nvgpu_clk_arb_run_vf_table_cb(struct work_struct *work);
41static int nvgpu_clk_arb_update_vf_table(struct nvgpu_clk_arb *arb);
42static void nvgpu_clk_arb_free_fd(struct kref *refcount);
43static void nvgpu_clk_arb_free_session(struct kref *refcount);
44static int nvgpu_clk_arb_change_vf_point(struct gk20a *g, u16 gpc2clk_target,
45 u16 sys2clk_target, u16 xbar2clk_target, u16 mclk_target, u32 voltuv,
46 u32 voltuv_sram);
47static u8 nvgpu_clk_arb_find_vf_point(struct nvgpu_clk_arb *arb,
48 u16 *gpc2clk, u16 *sys2clk, u16 *xbar2clk, u16 *mclk,
49 u32 *voltuv, u32 *voltuv_sram, u32 *nuvmin, u32 *nuvmin_sram);
50
51#define VF_POINT_INVALID_PSTATE ~0U
52#define VF_POINT_SET_PSTATE_SUPPORTED(a, b) ((a)->pstates |= (1UL << (b)))
53#define VF_POINT_GET_PSTATE(a) (((a)->pstates) ?\
54 __fls((a)->pstates) :\
55 VF_POINT_INVALID_PSTATE)
56#define VF_POINT_COMMON_PSTATE(a, b) (((a)->pstates & (b)->pstates) ?\
57 __fls((a)->pstates & (b)->pstates) :\
58 VF_POINT_INVALID_PSTATE)
59
60struct nvgpu_clk_vf_point {
61 u16 pstates;
62 union {
63 struct {
64 u16 gpc_mhz;
65 u16 sys_mhz;
66 u16 xbar_mhz;
67 };
68 u16 mem_mhz;
69 };
70 u32 uvolt;
71 u32 uvolt_sram;
72};
73
74struct nvgpu_clk_vf_table {
75 u32 mclk_num_points;
76 struct nvgpu_clk_vf_point *mclk_points;
77 u32 gpc2clk_num_points;
78 struct nvgpu_clk_vf_point *gpc2clk_points;
79};
80#ifdef CONFIG_DEBUG_FS
81struct nvgpu_clk_arb_debug {
82 s64 switch_max;
83 s64 switch_min;
84 u64 switch_num;
85 s64 switch_avg;
86 s64 switch_std;
87};
88#endif
89
90struct nvgpu_clk_arb_target {
91 u16 mclk;
92 u16 gpc2clk;
93 u32 pstate;
94};
95
96struct nvgpu_clk_arb {
97 spinlock_t sessions_lock;
98 spinlock_t users_lock;
99
100 struct mutex pstate_lock;
101 struct list_head users;
102 struct list_head sessions;
103 struct llist_head requests;
104
105 struct gk20a *g;
106 int status;
107
108 struct nvgpu_clk_arb_target actual_pool[2];
109 struct nvgpu_clk_arb_target *actual;
110
111 u16 gpc2clk_default_mhz;
112 u16 mclk_default_mhz;
113 u32 voltuv_actual;
114
115 struct work_struct update_fn_work;
116 struct workqueue_struct *update_work_queue;
117 struct work_struct vf_table_fn_work;
118 struct workqueue_struct *vf_table_work_queue;
119
120 wait_queue_head_t request_wq;
121
122 struct nvgpu_clk_vf_table *current_vf_table;
123 struct nvgpu_clk_vf_table vf_table_pool[2];
124 u32 vf_table_index;
125
126 u16 *mclk_f_points;
127 atomic_t req_nr;
128
129 u32 mclk_f_numpoints;
130 u16 *gpc2clk_f_points;
131 u32 gpc2clk_f_numpoints;
132
133#ifdef CONFIG_DEBUG_FS
134 struct nvgpu_clk_arb_debug debug_pool[2];
135 struct nvgpu_clk_arb_debug *debug;
136 bool debugfs_set;
137#endif
138};
139
140struct nvgpu_clk_dev {
141 struct nvgpu_clk_session *session;
142 union {
143 struct list_head link;
144 struct llist_node node;
145 };
146 wait_queue_head_t readout_wq;
147 atomic_t poll_mask;
148 u16 gpc2clk_target_mhz;
149 u16 mclk_target_mhz;
150 struct kref refcount;
151};
152
153struct nvgpu_clk_session {
154 bool zombie;
155 struct gk20a *g;
156 struct kref refcount;
157 struct list_head link;
158 struct llist_head targets;
159
160 struct nvgpu_clk_arb_target target_pool[2];
161 struct nvgpu_clk_arb_target *target;
162};
163
164static const struct file_operations completion_dev_ops = {
165 .owner = THIS_MODULE,
166 .release = nvgpu_clk_arb_release_completion_dev,
167 .poll = nvgpu_clk_arb_poll_dev,
168};
169
170static const struct file_operations event_dev_ops = {
171 .owner = THIS_MODULE,
172 .release = nvgpu_clk_arb_release_event_dev,
173 .poll = nvgpu_clk_arb_poll_dev,
174};
175
176int nvgpu_clk_arb_init_arbiter(struct gk20a *g)
177{
178 struct nvgpu_clk_arb *arb;
179 u16 default_mhz;
180 int err;
181 int index;
182 struct nvgpu_clk_vf_table *table;
183
184 gk20a_dbg_fn("");
185
186 if (!g->ops.clk_arb.get_arbiter_clk_domains)
187 return 0;
188
189 arb = kzalloc(sizeof(struct nvgpu_clk_arb), GFP_KERNEL);
190 if (!arb) {
191 err = -ENOMEM;
192 goto init_fail;
193 }
194
195 arb->mclk_f_points = kcalloc(MAX_F_POINTS, sizeof(u16), GFP_KERNEL);
196 if (!arb->mclk_f_points) {
197 err = -ENOMEM;
198 goto init_fail;
199 }
200
201 arb->gpc2clk_f_points = kcalloc(MAX_F_POINTS, sizeof(u16), GFP_KERNEL);
202 if (!arb->gpc2clk_f_points) {
203 err = -ENOMEM;
204 goto init_fail;
205 }
206
207 for (index = 0; index < 2; index++) {
208 table = &arb->vf_table_pool[index];
209 table->gpc2clk_num_points = MAX_F_POINTS;
210 table->mclk_num_points = MAX_F_POINTS;
211
212 table->gpc2clk_points = kcalloc(MAX_F_POINTS,
213 sizeof(struct nvgpu_clk_vf_point), GFP_KERNEL);
214 if (!table->gpc2clk_points) {
215 err = -ENOMEM;
216 goto init_fail;
217 }
218
219
220 table->mclk_points = kcalloc(MAX_F_POINTS,
221 sizeof(struct nvgpu_clk_vf_point), GFP_KERNEL);
222 if (!table->mclk_points) {
223 err = -ENOMEM;
224 goto init_fail;
225 }
226 }
227
228 g->clk_arb = arb;
229 arb->g = g;
230
231 mutex_init(&arb->pstate_lock);
232 spin_lock_init(&arb->sessions_lock);
233 spin_lock_init(&arb->users_lock);
234
235 err = g->ops.clk_arb.get_arbiter_clk_default(g,
236 NVGPU_GPU_CLK_DOMAIN_MCLK, &default_mhz);
237 if (err) {
238 err = -EINVAL;
239 goto init_fail;
240 }
241
242 arb->mclk_default_mhz = default_mhz;
243
244 err = g->ops.clk_arb.get_arbiter_clk_default(g,
245 NVGPU_GPU_CLK_DOMAIN_GPC2CLK, &default_mhz);
246 if (err) {
247 err = -EINVAL;
248 goto init_fail;
249 }
250
251 arb->gpc2clk_default_mhz = default_mhz;
252
253 arb->actual = &arb->actual_pool[0];
254
255 atomic_set(&arb->req_nr, 0);
256
257 INIT_LIST_HEAD_RCU(&arb->users);
258 INIT_LIST_HEAD_RCU(&arb->sessions);
259 init_llist_head(&arb->requests);
260
261 init_waitqueue_head(&arb->request_wq);
262 arb->vf_table_work_queue = alloc_workqueue("%s", WQ_HIGHPRI, 1,
263 "vf_table_update");
264 arb->update_work_queue = alloc_workqueue("%s", WQ_HIGHPRI, 1,
265 "arbiter_update");
266
267
268 INIT_WORK(&arb->vf_table_fn_work, nvgpu_clk_arb_run_vf_table_cb);
269
270 INIT_WORK(&arb->update_fn_work, nvgpu_clk_arb_run_arbiter_cb);
271
272#ifdef CONFIG_DEBUG_FS
273 arb->debug = &arb->debug_pool[0];
274
275 if (!arb->debugfs_set) {
276 if (nvgpu_clk_arb_debugfs_init(g))
277 arb->debugfs_set = true;
278 }
279#endif
280 err = clk_vf_point_cache(g);
281 if (err < 0)
282 goto init_fail;
283
284 err = nvgpu_clk_arb_update_vf_table(arb);
285 if (err < 0)
286 goto init_fail;
287 do {
288 /* Check that first run is completed */
289 smp_mb();
290 wait_event_interruptible(arb->request_wq,
291 atomic_read(&arb->req_nr));
292 } while (!atomic_read(&arb->req_nr));
293
294
295 return arb->status;
296
297init_fail:
298
299 kfree(arb->gpc2clk_f_points);
300 kfree(arb->mclk_f_points);
301
302 for (index = 0; index < 2; index++) {
303 kfree(arb->vf_table_pool[index].gpc2clk_points);
304 kfree(arb->vf_table_pool[index].mclk_points);
305 }
306
307 kfree(arb);
308
309 return err;
310}
311
312void nvgpu_clk_arb_cleanup_arbiter(struct gk20a *g)
313{
314 kfree(g->clk_arb);
315}
316
317static int nvgpu_clk_arb_install_fd(struct gk20a *g,
318 struct nvgpu_clk_session *session,
319 const struct file_operations *fops,
320 struct nvgpu_clk_dev **_dev)
321{
322 struct file *file;
323 char *name;
324 int fd;
325 int err;
326 struct nvgpu_clk_dev *dev;
327
328 gk20a_dbg_fn("");
329
330 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
331 if (!dev)
332 return -ENOMEM;
333
334 fd = get_unused_fd_flags(O_RDWR);
335 if (fd < 0)
336 return fd;
337
338 name = kasprintf(GFP_KERNEL, "%s-clk-fd%d", dev_name(g->dev), fd);
339 file = anon_inode_getfile(name, fops, dev, O_RDWR);
340 kfree(name);
341 if (IS_ERR(file)) {
342 err = PTR_ERR(file);
343 goto fail;
344 }
345
346 fd_install(fd, file);
347
348 init_waitqueue_head(&dev->readout_wq);
349 atomic_set(&dev->poll_mask, 0);
350
351 dev->session = session;
352 kref_init(&dev->refcount);
353
354 kref_get(&session->refcount);
355
356 *_dev = dev;
357
358 return fd;
359
360fail:
361 kfree(dev);
362 put_unused_fd(fd);
363
364 return err;
365}
366
367int nvgpu_clk_arb_init_session(struct gk20a *g,
368 struct nvgpu_clk_session **_session)
369{
370 struct nvgpu_clk_arb *arb = g->clk_arb;
371 struct nvgpu_clk_session *session = *(_session);
372
373 gk20a_dbg_fn("");
374
375 if (!g->ops.clk_arb.get_arbiter_clk_domains)
376 return 0;
377
378 session = kzalloc(sizeof(struct nvgpu_clk_session), GFP_KERNEL);
379 if (!session)
380 return -ENOMEM;
381 session->g = g;
382
383 kref_init(&session->refcount);
384
385 session->zombie = false;
386 session->target_pool[0].pstate = CTRL_PERF_PSTATE_P8;
387 /* make sure that the initialization of the pool is visible
388 * before the update */
389 smp_wmb();
390 session->target = &session->target_pool[0];
391
392 init_llist_head(&session->targets);
393
394 spin_lock(&arb->sessions_lock);
395 list_add_tail_rcu(&session->link, &arb->sessions);
396 spin_unlock(&arb->sessions_lock);
397
398 *_session = session;
399
400 return 0;
401}
402
403static void nvgpu_clk_arb_free_fd(struct kref *refcount)
404{
405 struct nvgpu_clk_dev *dev = container_of(refcount,
406 struct nvgpu_clk_dev, refcount);
407
408 kfree(dev);
409}
410
411static void nvgpu_clk_arb_free_session(struct kref *refcount)
412{
413 struct nvgpu_clk_session *session = container_of(refcount,
414 struct nvgpu_clk_session, refcount);
415 struct nvgpu_clk_arb *arb = session->g->clk_arb;
416 struct nvgpu_clk_dev *dev, *tmp;
417 struct llist_node *head;
418
419 gk20a_dbg_fn("");
420
421 spin_lock(&arb->sessions_lock);
422 list_del_rcu(&session->link);
423 spin_unlock(&arb->sessions_lock);
424
425 head = llist_del_all(&session->targets);
426 llist_for_each_entry_safe(dev, tmp, head, node) {
427 kref_put(&dev->refcount, nvgpu_clk_arb_free_fd);
428 }
429 synchronize_rcu();
430 kfree(session);
431}
432
433void nvgpu_clk_arb_release_session(struct gk20a *g,
434 struct nvgpu_clk_session *session)
435{
436 struct nvgpu_clk_arb *arb = g->clk_arb;
437
438 gk20a_dbg_fn("");
439
440 session->zombie = true;
441 kref_put(&session->refcount, nvgpu_clk_arb_free_session);
442
443 queue_work(arb->update_work_queue, &arb->update_fn_work);
444}
445
446int nvgpu_clk_arb_install_event_fd(struct gk20a *g,
447 struct nvgpu_clk_session *session, int *event_fd)
448{
449 struct nvgpu_clk_arb *arb = g->clk_arb;
450 struct nvgpu_clk_dev *dev;
451 int fd;
452
453 gk20a_dbg_fn("");
454
455 fd = nvgpu_clk_arb_install_fd(g, session, &event_dev_ops, &dev);
456 if (fd < 0)
457 return fd;
458
459 spin_lock(&arb->users_lock);
460 list_add_tail_rcu(&dev->link, &arb->users);
461 spin_unlock(&arb->users_lock);
462
463 *event_fd = fd;
464
465 return 0;
466}
467
468int nvgpu_clk_arb_install_request_fd(struct gk20a *g,
469 struct nvgpu_clk_session *session, int *request_fd)
470{
471 struct nvgpu_clk_dev *dev;
472 int fd;
473
474 gk20a_dbg_fn("");
475
476 fd = nvgpu_clk_arb_install_fd(g, session, &completion_dev_ops, &dev);
477 if (fd < 0)
478 return fd;
479
480 *request_fd = fd;
481
482 return 0;
483}
484
485static int nvgpu_clk_arb_update_vf_table(struct nvgpu_clk_arb *arb)
486{
487 struct gk20a *g = arb->g;
488 struct nvgpu_clk_vf_table *table;
489
490 u32 i, j;
491 int status = -EINVAL;
492 u32 gpc2clk_voltuv = 0, mclk_voltuv = 0;
493 u32 gpc2clk_voltuv_sram = 0, mclk_voltuv_sram = 0;
494 u16 gpc2clk_min, gpc2clk_max, clk_cur;
495 u16 mclk_min, mclk_max;
496 u32 num_points;
497
498 struct clk_set_info *p5_info, *p0_info;
499
500
501 table = ACCESS_ONCE(arb->current_vf_table);
502 /* make flag visible when all data has resolved in the tables */
503 smp_rmb();
504
505 table = (table == &arb->vf_table_pool[0]) ? &arb->vf_table_pool[1] :
506 &arb->vf_table_pool[0];
507
508 /* Get allowed memory ranges */
509 if (nvgpu_clk_arb_get_arbiter_clk_range(g, NVGPU_GPU_CLK_DOMAIN_GPC2CLK,
510 &gpc2clk_min,
511 &gpc2clk_max) < 0) {
512 gk20a_err(dev_from_gk20a(g),
513 "failed to fetch GPC2CLK range");
514 goto exit_vf_table;
515 }
516 if (nvgpu_clk_arb_get_arbiter_clk_range(g, NVGPU_GPU_CLK_DOMAIN_MCLK,
517 &mclk_min, &mclk_max) < 0) {
518 gk20a_err(dev_from_gk20a(g),
519 "failed to fetch MCLK range");
520 goto exit_vf_table;
521 }
522
523 if (clk_domain_get_f_points(arb->g, NVGPU_GPU_CLK_DOMAIN_GPC2CLK,
524 &table->gpc2clk_num_points, arb->gpc2clk_f_points)) {
525 gk20a_err(dev_from_gk20a(g),
526 "failed to fetch GPC2CLK frequency points");
527 goto exit_vf_table;
528 }
529
530 table->gpc2clk_num_points = MAX_F_POINTS;
531 table->mclk_num_points = MAX_F_POINTS;
532
533 if (clk_domain_get_f_points(arb->g, NVGPU_GPU_CLK_DOMAIN_MCLK,
534 &table->mclk_num_points, arb->mclk_f_points)) {
535 gk20a_err(dev_from_gk20a(g),
536 "failed to fetch MCLK frequency points");
537 goto exit_vf_table;
538 }
539 if (!table->mclk_num_points || !table->gpc2clk_num_points) {
540 gk20a_err(dev_from_gk20a(g),
541 "empty queries to f points mclk %d gpc2clk %d",
542 table->mclk_num_points, table->gpc2clk_num_points);
543 status = -EINVAL;
544 goto exit_vf_table;
545 }
546
547 memset(table->mclk_points, 0,
548 table->mclk_num_points*sizeof(struct nvgpu_clk_vf_point));
549 memset(table->gpc2clk_points, 0,
550 table->gpc2clk_num_points*sizeof(struct nvgpu_clk_vf_point));
551
552 p5_info = pstate_get_clk_set_info(g,
553 CTRL_PERF_PSTATE_P5, clkwhich_mclk);
554 if (!p5_info) {
555 gk20a_err(dev_from_gk20a(g),
556 "failed to get MCLK P5 info");
557 goto exit_vf_table;
558 }
559 p0_info = pstate_get_clk_set_info(g,
560 CTRL_PERF_PSTATE_P0, clkwhich_mclk);
561 if (!p0_info) {
562 gk20a_err(dev_from_gk20a(g),
563 "failed to get MCLK P0 info");
564 goto exit_vf_table;
565 }
566
567 for (i = 0, j = 0, num_points = 0, clk_cur = 0;
568 i < table->mclk_num_points; i++) {
569
570 if ((arb->mclk_f_points[i] >= mclk_min) &&
571 (arb->mclk_f_points[i] <= mclk_max) &&
572 (arb->mclk_f_points[i] != clk_cur)) {
573
574 table->mclk_points[j].mem_mhz = arb->mclk_f_points[i];
575 mclk_voltuv = mclk_voltuv_sram = 0;
576
577 status = clk_domain_get_f_or_v(g, CTRL_CLK_DOMAIN_MCLK,
578 &table->mclk_points[j].mem_mhz, &mclk_voltuv,
579 CTRL_VOLT_DOMAIN_LOGIC);
580 if (status < 0) {
581 gk20a_err(dev_from_gk20a(g),
582 "failed to get MCLK LOGIC voltage");
583 goto exit_vf_table;
584 }
585 status = clk_domain_get_f_or_v(g, CTRL_CLK_DOMAIN_MCLK,
586 &table->mclk_points[j].mem_mhz,
587 &mclk_voltuv_sram,
588 CTRL_VOLT_DOMAIN_SRAM);
589 if (status < 0) {
590 gk20a_err(dev_from_gk20a(g),
591 "failed to get MCLK SRAM voltage");
592 goto exit_vf_table;
593 }
594
595 table->mclk_points[j].uvolt = mclk_voltuv;
596 table->mclk_points[j].uvolt_sram = mclk_voltuv_sram;
597 clk_cur = table->mclk_points[j].mem_mhz;
598
599 if ((clk_cur >= p5_info->min_mhz) &&
600 (clk_cur <= p5_info->max_mhz))
601 VF_POINT_SET_PSTATE_SUPPORTED(
602 &table->mclk_points[j],
603 CTRL_PERF_PSTATE_P5);
604 if ((clk_cur >= p0_info->min_mhz) &&
605 (clk_cur <= p0_info->max_mhz))
606 VF_POINT_SET_PSTATE_SUPPORTED(
607 &table->mclk_points[j],
608 CTRL_PERF_PSTATE_P0);
609
610 j++;
611 num_points++;
612
613 }
614 }
615 table->mclk_num_points = num_points;
616
617 p5_info = pstate_get_clk_set_info(g,
618 CTRL_PERF_PSTATE_P5, clkwhich_gpc2clk);
619 if (!p5_info) {
620 status = -EINVAL;
621 gk20a_err(dev_from_gk20a(g),
622 "failed to get GPC2CLK P5 info");
623 goto exit_vf_table;
624 }
625
626 p0_info = pstate_get_clk_set_info(g,
627 CTRL_PERF_PSTATE_P0, clkwhich_gpc2clk);
628 if (!p0_info) {
629 status = -EINVAL;
630 gk20a_err(dev_from_gk20a(g),
631 "failed to get GPC2CLK P0 info");
632 goto exit_vf_table;
633 }
634
635 /* GPC2CLK needs to be checked in two passes. The first determines the
636 * relationships between GPC2CLK, SYS2CLK and XBAR2CLK, while the
637 * second verifies that the clocks minimum is satisfied and sets
638 * the voltages
639 */
640 for (i = 0, j = 0, num_points = 0, clk_cur = 0;
641 i < table->gpc2clk_num_points; i++) {
642 struct set_fll_clk setfllclk;
643
644 if ((arb->gpc2clk_f_points[i] >= gpc2clk_min) &&
645 (arb->gpc2clk_f_points[i] <= gpc2clk_max) &&
646 (arb->gpc2clk_f_points[i] != clk_cur)) {
647
648 table->gpc2clk_points[j].gpc_mhz =
649 arb->gpc2clk_f_points[i];
650 setfllclk.gpc2clkmhz = arb->gpc2clk_f_points[i];
651 status = clk_get_fll_clks(g, &setfllclk);
652 if (status < 0) {
653 gk20a_err(dev_from_gk20a(g),
654 "failed to get GPC2CLK slave clocks");
655 goto exit_vf_table;
656 }
657
658 table->gpc2clk_points[j].sys_mhz =
659 setfllclk.sys2clkmhz;
660 table->gpc2clk_points[j].xbar_mhz =
661 setfllclk.xbar2clkmhz;
662
663 clk_cur = table->gpc2clk_points[j].gpc_mhz;
664
665 if ((clk_cur >= p5_info->min_mhz) &&
666 (clk_cur <= p5_info->max_mhz))
667 VF_POINT_SET_PSTATE_SUPPORTED(
668 &table->gpc2clk_points[j],
669 CTRL_PERF_PSTATE_P5);
670 if ((clk_cur >= p0_info->min_mhz) &&
671 (clk_cur <= p0_info->max_mhz))
672 VF_POINT_SET_PSTATE_SUPPORTED(
673 &table->gpc2clk_points[j],
674 CTRL_PERF_PSTATE_P0);
675
676 j++;
677 num_points++;
678 }
679 }
680 table->gpc2clk_num_points = num_points;
681
682 /* Second pass */
683 for (i = 0, j = 0; i < table->gpc2clk_num_points; i++) {
684
685 u16 alt_gpc2clk = table->gpc2clk_points[i].gpc_mhz;
686 gpc2clk_voltuv = gpc2clk_voltuv_sram = 0;
687
688 /* Check sysclk */
689 p5_info = pstate_get_clk_set_info(g,
690 VF_POINT_GET_PSTATE(&table->gpc2clk_points[i]),
691 clkwhich_sys2clk);
692 if (!p5_info) {
693 status = -EINVAL;
694 gk20a_err(dev_from_gk20a(g),
695 "failed to get SYS2CLK P5 info");
696 goto exit_vf_table;
697 }
698
699 /* sys2clk below clk min, need to find correct clock */
700 if (table->gpc2clk_points[i].sys_mhz < p5_info->min_mhz) {
701 for (j = i + 1; j < table->gpc2clk_num_points; j++) {
702
703 if (table->gpc2clk_points[j].sys_mhz >=
704 p5_info->min_mhz) {
705
706
707 table->gpc2clk_points[i].sys_mhz =
708 p5_info->min_mhz;
709
710 alt_gpc2clk = alt_gpc2clk <
711 table->gpc2clk_points[j].
712 gpc_mhz ?
713 table->gpc2clk_points[j].
714 gpc_mhz:
715 alt_gpc2clk;
716 break;
717 }
718 }
719 /* no VF exists that satisfies condition */
720 if (j == table->gpc2clk_num_points) {
721 gk20a_err(dev_from_gk20a(g),
722 "NO SYS2CLK VF point possible");
723 status = -EINVAL;
724 goto exit_vf_table;
725 }
726 }
727
728 /* Check xbarclk */
729 p5_info = pstate_get_clk_set_info(g,
730 VF_POINT_GET_PSTATE(&table->gpc2clk_points[i]),
731 clkwhich_xbar2clk);
732 if (!p5_info) {
733 status = -EINVAL;
734 gk20a_err(dev_from_gk20a(g),
735 "failed to get SYS2CLK P5 info");
736 goto exit_vf_table;
737 }
738
739 /* xbar2clk below clk min, need to find correct clock */
740 if (table->gpc2clk_points[i].xbar_mhz < p5_info->min_mhz) {
741 for (j = i; j < table->gpc2clk_num_points; j++) {
742 if (table->gpc2clk_points[j].xbar_mhz >=
743 p5_info->min_mhz) {
744
745 table->gpc2clk_points[i].xbar_mhz =
746 p5_info->min_mhz;
747
748 alt_gpc2clk = alt_gpc2clk <
749 table->gpc2clk_points[j].
750 gpc_mhz ?
751 table->gpc2clk_points[j].
752 gpc_mhz:
753 alt_gpc2clk;
754 break;
755 }
756 }
757 /* no VF exists that satisfies condition */
758 if (j == table->gpc2clk_num_points) {
759 status = -EINVAL;
760 gk20a_err(dev_from_gk20a(g),
761 "NO XBAR2CLK VF point possible");
762
763 goto exit_vf_table;
764 }
765 }
766
767 /* Calculate voltages */
768 status = clk_domain_get_f_or_v(g, CTRL_CLK_DOMAIN_GPC2CLK,
769 &alt_gpc2clk, &gpc2clk_voltuv,
770 CTRL_VOLT_DOMAIN_LOGIC);
771 if (status < 0) {
772 gk20a_err(dev_from_gk20a(g),
773 "failed to get GPC2CLK LOGIC voltage");
774 goto exit_vf_table;
775 }
776
777 status = clk_domain_get_f_or_v(g, CTRL_CLK_DOMAIN_GPC2CLK,
778 &alt_gpc2clk,
779 &gpc2clk_voltuv_sram,
780 CTRL_VOLT_DOMAIN_SRAM);
781 if (status < 0) {
782 gk20a_err(dev_from_gk20a(g),
783 "failed to get GPC2CLK SRAM voltage");
784 goto exit_vf_table;
785 }
786
787 table->gpc2clk_points[i].uvolt = gpc2clk_voltuv;
788 table->gpc2clk_points[i].uvolt_sram = gpc2clk_voltuv_sram;
789 }
790
791 /* make table visible when all data has resolved in the tables */
792 smp_wmb();
793 xchg(&arb->current_vf_table, table);
794
795 queue_work(arb->update_work_queue, &arb->update_fn_work);
796exit_vf_table:
797
798 return status;
799}
800
801void nvgpu_clk_arb_schedule_vf_table_update(struct gk20a *g)
802{
803 struct nvgpu_clk_arb *arb = g->clk_arb;
804
805 queue_work(arb->vf_table_work_queue, &arb->vf_table_fn_work);
806}
807
808static void nvgpu_clk_arb_run_vf_table_cb(struct work_struct *work)
809{
810 struct nvgpu_clk_arb *arb =
811 container_of(work, struct nvgpu_clk_arb, vf_table_fn_work);
812 struct gk20a *g = arb->g;
813 u32 err;
814
815 /* get latest vf curve from pmu */
816 err = clk_vf_point_cache(g);
817 if (err) {
818 gk20a_err(dev_from_gk20a(g),
819 "failed to cache VF table");
820 return;
821 }
822 nvgpu_clk_arb_update_vf_table(arb);
823}
824
825static void nvgpu_clk_arb_run_arbiter_cb(struct work_struct *work)
826{
827 struct nvgpu_clk_arb *arb =
828 container_of(work, struct nvgpu_clk_arb, update_fn_work);
829 struct nvgpu_clk_session *session;
830 struct nvgpu_clk_dev *dev;
831 struct nvgpu_clk_dev *tmp;
832 struct nvgpu_clk_arb_target *target, *actual;
833 struct gk20a *g = arb->g;
834 struct llist_node *head;
835
836 u32 pstate = VF_POINT_INVALID_PSTATE;
837 u32 voltuv, voltuv_sram;
838 bool mclk_set, gpc2clk_set;
839 u32 nuvmin, nuvmin_sram;
840
841 int status = 0;
842
843 /* Temporary variables for checking target frequency */
844 u16 gpc2clk_target, sys2clk_target, xbar2clk_target, mclk_target;
845
846#ifdef CONFIG_DEBUG_FS
847 u64 t0, t1;
848 struct nvgpu_clk_arb_debug *debug;
849
850#endif
851
852 gk20a_dbg_fn("");
853
854#ifdef CONFIG_DEBUG_FS
855 g->ops.read_ptimer(g, &t0);
856#endif
857
858 /* Only one arbiter should be running */
859 gpc2clk_target = 0;
860 mclk_target = 0;
861
862 rcu_read_lock();
863 list_for_each_entry_rcu(session, &arb->sessions, link) {
864 if (!session->zombie) {
865 mclk_set = false;
866 gpc2clk_set = false;
867 target = ACCESS_ONCE(session->target) ==
868 &session->target_pool[0] ?
869 &session->target_pool[1] :
870 &session->target_pool[0];
871 /* Do not reorder pointer */
872 smp_rmb();
873 head = llist_del_all(&session->targets);
874 if (head) {
875
876 /* Copy over state */
877 target->mclk = session->target->mclk;
878 target->gpc2clk = session->target->gpc2clk;
879 /* Query the latest committed request */
880 llist_for_each_entry_safe(dev, tmp, head,
881 node) {
882 if (!mclk_set && dev->mclk_target_mhz) {
883 target->mclk =
884 dev->mclk_target_mhz;
885 mclk_set = true;
886 }
887 if (!gpc2clk_set &&
888 dev->gpc2clk_target_mhz) {
889 target->gpc2clk =
890 dev->gpc2clk_target_mhz;
891 gpc2clk_set = true;
892 }
893 kref_get(&dev->refcount);
894 llist_add(&dev->node, &arb->requests);
895 }
896 /* Ensure target is updated before ptr sawp */
897 smp_wmb();
898 xchg(&session->target, target);
899 }
900
901 mclk_target = mclk_target > session->target->mclk ?
902 mclk_target : session->target->mclk;
903
904 gpc2clk_target =
905 gpc2clk_target > session->target->gpc2clk ?
906 gpc2clk_target : session->target->gpc2clk;
907 }
908 }
909 rcu_read_unlock();
910
911 gpc2clk_target = (gpc2clk_target > 0) ? gpc2clk_target :
912 arb->gpc2clk_default_mhz;
913
914 mclk_target = (mclk_target > 0) ? mclk_target:
915 arb->mclk_default_mhz;
916
917 sys2clk_target = 0;
918 xbar2clk_target = 0;
919 /* Query the table for the closest vf point to program */
920 pstate = nvgpu_clk_arb_find_vf_point(arb, &gpc2clk_target,
921 &sys2clk_target, &xbar2clk_target, &mclk_target, &voltuv,
922 &voltuv_sram, &nuvmin, &nuvmin_sram);
923
924 if (pstate == VF_POINT_INVALID_PSTATE) {
925 arb->status = -EINVAL;
926 /* make status visible */
927 smp_mb();
928 goto exit_arb;
929 }
930
931 if ((arb->actual->gpc2clk == gpc2clk_target) &&
932 (arb->actual->mclk == mclk_target) &&
933 (arb->voltuv_actual == voltuv)) {
934 goto exit_arb;
935 }
936
937 /* Program clocks */
938 /* A change in both mclk of gpc2clk may require a change in voltage */
939
940 mutex_lock(&arb->pstate_lock);
941 status = nvgpu_lpwr_disable_pg(g, false);
942
943 status = clk_pmu_freq_controller_load(g, false);
944 if (status < 0) {
945 arb->status = status;
946 mutex_unlock(&arb->pstate_lock);
947
948 /* make status visible */
949 smp_mb();
950 goto exit_arb;
951 }
952 status = volt_set_noiseaware_vmin(g, nuvmin, nuvmin_sram);
953 if (status < 0) {
954 arb->status = status;
955 mutex_unlock(&arb->pstate_lock);
956
957 /* make status visible */
958 smp_mb();
959 goto exit_arb;
960 }
961
962 status = nvgpu_clk_arb_change_vf_point(g, gpc2clk_target,
963 sys2clk_target, xbar2clk_target, mclk_target, voltuv,
964 voltuv_sram);
965 if (status < 0) {
966 arb->status = status;
967 mutex_unlock(&arb->pstate_lock);
968
969 /* make status visible */
970 smp_mb();
971 goto exit_arb;
972 }
973
974 status = clk_pmu_freq_controller_load(g, true);
975 if (status < 0) {
976 arb->status = status;
977 mutex_unlock(&arb->pstate_lock);
978
979 /* make status visible */
980 smp_mb();
981 goto exit_arb;
982 }
983
984 status = nvgpu_lwpr_mclk_change(g, pstate);
985 if (status < 0) {
986 arb->status = status;
987 mutex_unlock(&arb->pstate_lock);
988
989 /* make status visible */
990 smp_mb();
991 goto exit_arb;
992 }
993
994 actual = ACCESS_ONCE(arb->actual) == &arb->actual_pool[0] ?
995 &arb->actual_pool[1] : &arb->actual_pool[0];
996
997 /* do not reorder this pointer */
998 smp_rmb();
999 actual->gpc2clk = gpc2clk_target;
1000 actual->mclk = mclk_target;
1001 arb->voltuv_actual = voltuv;
1002 actual->pstate = pstate;
1003 arb->status = status;
1004
1005 /* Make changes visible to other threads */
1006 smp_wmb();
1007 xchg(&arb->actual, actual);
1008
1009 status = nvgpu_lpwr_enable_pg(g, false);
1010 if (status < 0) {
1011 arb->status = status;
1012 mutex_unlock(&arb->pstate_lock);
1013
1014 /* make status visible */
1015 smp_mb();
1016 goto exit_arb;
1017 }
1018
1019 /* status must be visible before atomic inc */
1020 smp_wmb();
1021 atomic_inc(&arb->req_nr);
1022
1023 /* Unlock pstate change for PG */
1024 mutex_unlock(&arb->pstate_lock);
1025
1026 wake_up_interruptible(&arb->request_wq);
1027
1028#ifdef CONFIG_DEBUG_FS
1029 g->ops.read_ptimer(g, &t1);
1030
1031 debug = arb->debug == &arb->debug_pool[0] ?
1032 &arb->debug_pool[1] : &arb->debug_pool[0];
1033
1034 memcpy(debug, arb->debug, sizeof(arb->debug_pool[0]));
1035 debug->switch_num++;
1036
1037 if (debug->switch_num == 1) {
1038 debug->switch_max = debug->switch_min =
1039 debug->switch_avg = (t1-t0)/1000;
1040 debug->switch_std = 0;
1041 } else {
1042 s64 prev_avg;
1043 s64 curr = (t1-t0)/1000;
1044
1045 debug->switch_max = curr > debug->switch_max ?
1046 curr : debug->switch_max;
1047 debug->switch_min = debug->switch_min ?
1048 (curr < debug->switch_min ?
1049 curr : debug->switch_min) : curr;
1050 prev_avg = debug->switch_avg;
1051 debug->switch_avg = (curr +
1052 (debug->switch_avg * (debug->switch_num-1))) /
1053 debug->switch_num;
1054 debug->switch_std +=
1055 (curr - debug->switch_avg) * (curr - prev_avg);
1056 }
1057 /* commit changes before exchanging debug pointer */
1058 smp_wmb();
1059 xchg(&arb->debug, debug);
1060#endif
1061
1062exit_arb:
1063 if (status < 0)
1064 gk20a_err(dev_from_gk20a(g),
1065 "Error in arbiter update");
1066
1067 /* notify completion for all requests */
1068 head = llist_del_all(&arb->requests);
1069 llist_for_each_entry_safe(dev, tmp, head, node) {
1070 atomic_set(&dev->poll_mask, POLLIN | POLLRDNORM);
1071 wake_up_interruptible(&dev->readout_wq);
1072 kref_put(&dev->refcount, nvgpu_clk_arb_free_fd);
1073 }
1074
1075 /* notify event for all users */
1076 rcu_read_lock();
1077 list_for_each_entry_rcu(dev, &arb->users, link) {
1078 atomic_set(&dev->poll_mask, POLLIN | POLLRDNORM);
1079 wake_up_interruptible(&dev->readout_wq);
1080 }
1081 rcu_read_unlock();
1082}
1083
1084int nvgpu_clk_arb_commit_request_fd(struct gk20a *g,
1085 struct nvgpu_clk_session *session, int request_fd)
1086{
1087 struct nvgpu_clk_arb *arb = g->clk_arb;
1088 struct nvgpu_clk_dev *dev;
1089 struct fd fd;
1090 int err = 0;
1091
1092 gk20a_dbg_fn("");
1093
1094 fd = fdget(request_fd);
1095
1096 if (!fd.file)
1097 return -EINVAL;
1098
1099 dev = (struct nvgpu_clk_dev *) fd.file->private_data;
1100
1101 if (!dev || dev->session != session) {
1102 err = -EINVAL;
1103 goto fdput_fd;
1104 }
1105 kref_get(&dev->refcount);
1106 llist_add(&dev->node, &session->targets);
1107
1108 queue_work(arb->update_work_queue, &arb->update_fn_work);
1109
1110fdput_fd:
1111 fdput(fd);
1112 return err;
1113}
1114
1115static unsigned int nvgpu_clk_arb_poll_dev(struct file *filp, poll_table *wait)
1116{
1117 struct nvgpu_clk_dev *dev = filp->private_data;
1118
1119 gk20a_dbg_fn("");
1120
1121 poll_wait(filp, &dev->readout_wq, wait);
1122 return atomic_xchg(&dev->poll_mask, 0);
1123}
1124
1125static int nvgpu_clk_arb_release_completion_dev(struct inode *inode,
1126 struct file *filp)
1127{
1128 struct nvgpu_clk_dev *dev = filp->private_data;
1129 struct nvgpu_clk_session *session = dev->session;
1130 struct nvgpu_clk_arb *arb;
1131
1132 arb = session->g->clk_arb;
1133
1134 gk20a_dbg_fn("");
1135
1136 kref_put(&session->refcount, nvgpu_clk_arb_free_session);
1137 kref_put(&dev->refcount, nvgpu_clk_arb_free_fd);
1138
1139 return 0;
1140}
1141
1142static int nvgpu_clk_arb_release_event_dev(struct inode *inode,
1143 struct file *filp)
1144{
1145 struct nvgpu_clk_dev *dev = filp->private_data;
1146 struct nvgpu_clk_session *session = dev->session;
1147 struct nvgpu_clk_arb *arb;
1148
1149 arb = session->g->clk_arb;
1150
1151 gk20a_dbg_fn("");
1152
1153 spin_lock(&arb->users_lock);
1154 list_del_rcu(&dev->link);
1155 spin_unlock(&arb->users_lock);
1156
1157 kref_put(&session->refcount, nvgpu_clk_arb_free_session);
1158 synchronize_rcu();
1159 kfree(dev);
1160
1161 return 0;
1162}
1163
1164int nvgpu_clk_arb_set_session_target_mhz(struct nvgpu_clk_session *session,
1165 int request_fd, u32 api_domain, u16 target_mhz)
1166{
1167 struct nvgpu_clk_dev *dev;
1168 struct fd fd;
1169 int err = 0;
1170
1171 gk20a_dbg_fn("domain=0x%08x target_mhz=%u", api_domain, target_mhz);
1172
1173 fd = fdget(request_fd);
1174
1175 if (!fd.file)
1176 return -EINVAL;
1177
1178 dev = fd.file->private_data;
1179 if (!dev || dev->session != session) {
1180 err = -EINVAL;
1181 goto fdput_fd;
1182 }
1183
1184 switch (api_domain) {
1185 case NVGPU_GPU_CLK_DOMAIN_MCLK:
1186 dev->mclk_target_mhz = target_mhz;
1187 break;
1188
1189 case NVGPU_GPU_CLK_DOMAIN_GPC2CLK:
1190 dev->gpc2clk_target_mhz = target_mhz;
1191 break;
1192
1193 default:
1194 err = -EINVAL;
1195 }
1196
1197fdput_fd:
1198 fdput(fd);
1199 return err;
1200}
1201
1202int nvgpu_clk_arb_get_session_target_mhz(struct nvgpu_clk_session *session,
1203 u32 api_domain, u16 *freq_mhz)
1204{
1205 int err = 0;
1206 struct nvgpu_clk_arb_target *target;
1207
1208 do {
1209 target = ACCESS_ONCE(session->target);
1210 /* no reordering of this pointer */
1211 smp_rmb();
1212
1213 switch (api_domain) {
1214 case NVGPU_GPU_CLK_DOMAIN_MCLK:
1215 *freq_mhz = target->mclk;
1216 break;
1217
1218 case NVGPU_GPU_CLK_DOMAIN_GPC2CLK:
1219 *freq_mhz = target->gpc2clk;
1220 break;
1221
1222 default:
1223 *freq_mhz = 0;
1224 err = -EINVAL;
1225 }
1226 } while (target != ACCESS_ONCE(session->target));
1227 return err;
1228}
1229
1230int nvgpu_clk_arb_get_arbiter_actual_mhz(struct gk20a *g,
1231 u32 api_domain, u16 *freq_mhz)
1232{
1233 struct nvgpu_clk_arb *arb = g->clk_arb;
1234 int err = 0;
1235 struct nvgpu_clk_arb_target *actual;
1236
1237 do {
1238 actual = ACCESS_ONCE(arb->actual);
1239 /* no reordering of this pointer */
1240 smp_rmb();
1241
1242 switch (api_domain) {
1243 case NVGPU_GPU_CLK_DOMAIN_MCLK:
1244 *freq_mhz = actual->mclk;
1245 break;
1246
1247 case NVGPU_GPU_CLK_DOMAIN_GPC2CLK:
1248 *freq_mhz = actual->gpc2clk;
1249 break;
1250
1251 default:
1252 *freq_mhz = 0;
1253 err = -EINVAL;
1254 }
1255 } while (actual != ACCESS_ONCE(arb->actual));
1256 return err;
1257}
1258
1259int nvgpu_clk_arb_get_arbiter_effective_mhz(struct gk20a *g,
1260 u32 api_domain, u16 *freq_mhz)
1261{
1262
1263 *freq_mhz = g->ops.clk.get_rate(g, api_domain);
1264 return 0;
1265}
1266
1267int nvgpu_clk_arb_get_arbiter_clk_range(struct gk20a *g, u32 api_domain,
1268 u16 *min_mhz, u16 *max_mhz)
1269{
1270 return g->ops.clk_arb.get_arbiter_clk_range(g, api_domain,
1271 min_mhz, max_mhz);
1272}
1273
1274u32 nvgpu_clk_arb_get_arbiter_clk_domains(struct gk20a *g)
1275{
1276 return g->ops.clk_arb.get_arbiter_clk_domains(g);
1277}
1278
1279int nvgpu_clk_arb_get_arbiter_clk_f_points(struct gk20a *g,
1280 u32 api_domain, u32 *max_points, u16 *fpoints)
1281{
1282 return (int)clk_domain_get_f_points(g, api_domain, max_points, fpoints);
1283}
1284
1285static u8 nvgpu_clk_arb_find_vf_point(struct nvgpu_clk_arb *arb,
1286 u16 *gpc2clk, u16 *sys2clk, u16 *xbar2clk, u16 *mclk,
1287 u32 *voltuv, u32 *voltuv_sram, u32 *nuvmin, u32 *nuvmin_sram)
1288{
1289 u16 gpc2clk_target, mclk_target;
1290 u32 gpc2clk_voltuv, gpc2clk_voltuv_sram;
1291 u32 mclk_voltuv, mclk_voltuv_sram;
1292 u32 pstate = VF_POINT_INVALID_PSTATE;
1293 struct nvgpu_clk_vf_table *table;
1294 u32 index, index_mclk;
1295 struct nvgpu_clk_vf_point *mclk_vf = NULL;
1296
1297 do {
1298 gpc2clk_target = *gpc2clk;
1299 mclk_target = *mclk;
1300 gpc2clk_voltuv = 0;
1301 gpc2clk_voltuv_sram = 0;
1302 mclk_voltuv = 0;
1303 mclk_voltuv_sram = 0;
1304
1305 table = ACCESS_ONCE(arb->current_vf_table);
1306 /* pointer to table can be updated by callback */
1307 smp_rmb();
1308
1309 if (!table)
1310 continue;
1311 if ((!table->gpc2clk_num_points) || (!table->mclk_num_points)) {
1312 gk20a_err(dev_from_gk20a(arb->g), "found empty table");
1313 goto find_exit;
1314 }
1315 /* First we check MCLK to find out which PSTATE we are
1316 * are requesting, and from there try to find the minimum
1317 * GPC2CLK on the same PSTATE that satisfies the request.
1318 * If no GPC2CLK can be found, then we need to up the PSTATE
1319 */
1320
1321recalculate_vf_point:
1322 for (index = 0; index < table->mclk_num_points; index++) {
1323 if (table->mclk_points[index].mem_mhz >= mclk_target) {
1324 mclk_vf = &table->mclk_points[index];
1325 break;
1326 }
1327 }
1328 if (index == table->mclk_num_points) {
1329 mclk_vf = &table->mclk_points[index-1];
1330 index = table->mclk_num_points - 1;
1331 }
1332 index_mclk = index;
1333
1334 /* round up the freq requests */
1335 for (index = 0; index < table->gpc2clk_num_points; index++) {
1336 pstate = VF_POINT_COMMON_PSTATE(
1337 &table->gpc2clk_points[index], mclk_vf);
1338
1339 if ((table->gpc2clk_points[index].gpc_mhz >=
1340 gpc2clk_target) &&
1341 (pstate != VF_POINT_INVALID_PSTATE)){
1342 gpc2clk_target =
1343 table->gpc2clk_points[index].gpc_mhz;
1344 *sys2clk =
1345 table->gpc2clk_points[index].sys_mhz;
1346 *xbar2clk =
1347 table->gpc2clk_points[index].xbar_mhz;
1348
1349 gpc2clk_voltuv =
1350 table->gpc2clk_points[index].uvolt;
1351 gpc2clk_voltuv_sram =
1352 table->gpc2clk_points[index].uvolt_sram;
1353 break;
1354 }
1355 }
1356
1357 if (index == table->gpc2clk_num_points) {
1358 pstate = VF_POINT_COMMON_PSTATE(
1359 &table->gpc2clk_points[index-1], mclk_vf);
1360 if (pstate != VF_POINT_INVALID_PSTATE) {
1361 gpc2clk_target =
1362 table->gpc2clk_points[index-1].gpc_mhz;
1363 *sys2clk =
1364 table->gpc2clk_points[index-1].sys_mhz;
1365 *xbar2clk =
1366 table->gpc2clk_points[index-1].xbar_mhz;
1367
1368 gpc2clk_voltuv =
1369 table->gpc2clk_points[index-1].uvolt;
1370 gpc2clk_voltuv_sram =
1371 table->gpc2clk_points[index-1].
1372 uvolt_sram;
1373 } else if (index_mclk >= table->mclk_num_points - 1) {
1374 /* There is no available combination of MCLK
1375 * and GPC2CLK, we need to fail this
1376 */
1377 gpc2clk_target = 0;
1378 mclk_target = 0;
1379 pstate = VF_POINT_INVALID_PSTATE;
1380 goto find_exit;
1381 } else {
1382 /* recalculate with higher PSTATE */
1383 gpc2clk_target = *gpc2clk;
1384 mclk_target = table->mclk_points[index_mclk+1].
1385 mem_mhz;
1386 goto recalculate_vf_point;
1387 }
1388 }
1389
1390 mclk_target = mclk_vf->mem_mhz;
1391 mclk_voltuv = mclk_vf->uvolt;
1392 mclk_voltuv_sram = mclk_vf->uvolt_sram;
1393
1394 } while (!table ||
1395 (ACCESS_ONCE(arb->current_vf_table) != table));
1396
1397find_exit:
1398 *voltuv = gpc2clk_voltuv > mclk_voltuv ? gpc2clk_voltuv : mclk_voltuv;
1399 *voltuv_sram = gpc2clk_voltuv_sram > mclk_voltuv_sram ?
1400 gpc2clk_voltuv_sram : mclk_voltuv_sram;
1401 /* noise unaware vmin */
1402 *nuvmin = mclk_voltuv;
1403 *nuvmin_sram = mclk_voltuv_sram;
1404 *gpc2clk = gpc2clk_target;
1405 *mclk = mclk_target;
1406 return pstate;
1407}
1408
1409/* This function is inherently unsafe to call while arbiter is running
1410 * arbiter must be blocked before calling this function */
1411int nvgpu_clk_arb_get_current_pstate(struct gk20a *g)
1412{
1413 return ACCESS_ONCE(g->clk_arb->actual->pstate);
1414}
1415
1416static int nvgpu_clk_arb_change_vf_point(struct gk20a *g, u16 gpc2clk_target,
1417 u16 sys2clk_target, u16 xbar2clk_target, u16 mclk_target, u32 voltuv,
1418 u32 voltuv_sram)
1419{
1420 struct set_fll_clk fllclk;
1421 struct nvgpu_clk_arb *arb = g->clk_arb;
1422 int status;
1423
1424 fllclk.gpc2clkmhz = gpc2clk_target;
1425 fllclk.sys2clkmhz = sys2clk_target;
1426 fllclk.xbar2clkmhz = xbar2clk_target;
1427
1428 fllclk.voltuv = voltuv;
1429
1430 /* if voltage ascends we do:
1431 * (1) FLL change
1432 * (2) Voltage change
1433 * (3) MCLK change
1434 * If it goes down
1435 * (1) MCLK change
1436 * (2) Voltage change
1437 * (3) FLL change
1438 */
1439
1440 /* descending */
1441 if (voltuv < arb->voltuv_actual) {
1442 status = g->clk_pmu.clk_mclk.change(g, mclk_target);
1443 if (status < 0)
1444 return status;
1445
1446 status = volt_set_voltage(g, voltuv, voltuv_sram);
1447 if (status < 0)
1448 return status;
1449
1450 status = clk_set_fll_clks(g, &fllclk);
1451 if (status < 0)
1452 return status;
1453 } else {
1454 status = clk_set_fll_clks(g, &fllclk);
1455 if (status < 0)
1456 return status;
1457
1458 status = volt_set_voltage(g, voltuv, voltuv_sram);
1459 if (status < 0)
1460 return status;
1461
1462 status = g->clk_pmu.clk_mclk.change(g, mclk_target);
1463 if (status < 0)
1464 return status;
1465 }
1466
1467 return 0;
1468}
1469
1470void nvgpu_clk_arb_pstate_change_lock(struct gk20a *g, bool lock)
1471{
1472 struct nvgpu_clk_arb *arb = g->clk_arb;
1473
1474 if (lock)
1475 mutex_lock(&arb->pstate_lock);
1476 else
1477 mutex_unlock(&arb->pstate_lock);
1478
1479}
1480
1481#ifdef CONFIG_DEBUG_FS
1482static int nvgpu_clk_arb_stats_show(struct seq_file *s, void *unused)
1483{
1484 struct gk20a *g = s->private;
1485 struct nvgpu_clk_arb *arb = g->clk_arb;
1486 struct nvgpu_clk_arb_debug *debug;
1487
1488 u64 num;
1489 s64 tmp, avg, std, max, min;
1490
1491 debug = ACCESS_ONCE(arb->debug);
1492 /* Make copy of structure and ensure no reordering */
1493 smp_rmb();
1494 if (!debug)
1495 return -EINVAL;
1496
1497 std = debug->switch_std;
1498 avg = debug->switch_avg;
1499 max = debug->switch_max;
1500 min = debug->switch_min;
1501 num = debug->switch_num;
1502
1503 tmp = std;
1504 do_div(tmp, num);
1505 seq_printf(s, "Number of transitions: %lld\n",
1506 num);
1507 seq_printf(s, "max / min : %lld / %lld usec\n",
1508 max, min);
1509 seq_printf(s, "avg / std : %lld / %ld usec\n",
1510 avg, int_sqrt(tmp));
1511
1512 return 0;
1513}
1514
1515static int nvgpu_clk_arb_stats_open(struct inode *inode, struct file *file)
1516{
1517 return single_open(file, nvgpu_clk_arb_stats_show, inode->i_private);
1518}
1519
1520static const struct file_operations nvgpu_clk_arb_stats_fops = {
1521 .open = nvgpu_clk_arb_stats_open,
1522 .read = seq_read,
1523 .llseek = seq_lseek,
1524 .release = single_release,
1525};
1526
1527
1528static int nvgpu_clk_arb_debugfs_init(struct gk20a *g)
1529{
1530 struct gk20a_platform *platform = dev_get_drvdata(g->dev);
1531
1532 struct dentry *gpu_root = platform->debugfs;
1533 struct dentry *d;
1534
1535 gk20a_dbg(gpu_dbg_info, "g=%p", g);
1536
1537 d = debugfs_create_file(
1538 "arb_stats",
1539 S_IRUGO,
1540 gpu_root,
1541 g,
1542 &nvgpu_clk_arb_stats_fops);
1543 if (!d)
1544 return -ENOMEM;
1545
1546 return 0;
1547}
1548#endif
diff --git a/drivers/gpu/nvgpu/clk/clk_arb.h b/drivers/gpu/nvgpu/clk/clk_arb.h
new file mode 100644
index 00000000..700804b3
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk_arb.h
@@ -0,0 +1,71 @@
1/*
2 * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 */
13
14#include "gk20a/gk20a.h"
15
16#ifndef _CLK_ARB_H_
17#define _CLK_ARB_H_
18
19struct nvgpu_clk_arb;
20struct nvgpu_clk_session;
21
22int nvgpu_clk_arb_init_arbiter(struct gk20a *g);
23
24int nvgpu_clk_arb_get_arbiter_clk_range(struct gk20a *g, u32 api_domain,
25 u16 *min_mhz, u16 *max_mhz);
26
27int nvgpu_clk_arb_get_arbiter_actual_mhz(struct gk20a *g,
28 u32 api_domain, u16 *actual_mhz);
29
30int nvgpu_clk_arb_get_arbiter_effective_mhz(struct gk20a *g,
31 u32 api_domain, u16 *effective_mhz);
32
33int nvgpu_clk_arb_get_arbiter_clk_f_points(struct gk20a *g,
34 u32 api_domain, u32 *max_points, u16 *fpoints);
35
36u32 nvgpu_clk_arb_get_arbiter_clk_domains(struct gk20a *g);
37
38void nvgpu_clk_arb_cleanup_arbiter(struct gk20a *g);
39
40int nvgpu_clk_arb_install_session_fd(struct gk20a *g,
41 struct nvgpu_clk_session *session);
42
43int nvgpu_clk_arb_init_session(struct gk20a *g,
44 struct nvgpu_clk_session **_session);
45
46void nvgpu_clk_arb_release_session(struct gk20a *g,
47 struct nvgpu_clk_session *session);
48
49int nvgpu_clk_arb_commit_request_fd(struct gk20a *g,
50 struct nvgpu_clk_session *session, int request_fd);
51
52int nvgpu_clk_arb_set_session_target_mhz(struct nvgpu_clk_session *session,
53 int fd, u32 api_domain, u16 target_mhz);
54
55int nvgpu_clk_arb_get_session_target_mhz(struct nvgpu_clk_session *session,
56 u32 api_domain, u16 *target_mhz);
57
58int nvgpu_clk_arb_install_event_fd(struct gk20a *g,
59 struct nvgpu_clk_session *session, int *event_fd);
60
61int nvgpu_clk_arb_install_request_fd(struct gk20a *g,
62 struct nvgpu_clk_session *session, int *event_fd);
63
64void nvgpu_clk_arb_schedule_vf_table_update(struct gk20a *g);
65
66int nvgpu_clk_arb_get_current_pstate(struct gk20a *g);
67
68void nvgpu_clk_arb_pstate_change_lock(struct gk20a *g, bool lock);
69
70#endif /* _CLK_ARB_H_ */
71
diff --git a/drivers/gpu/nvgpu/clk/clk_domain.c b/drivers/gpu/nvgpu/clk/clk_domain.c
new file mode 100644
index 00000000..fe3db5d6
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk_domain.c
@@ -0,0 +1,1113 @@
1/*
2 * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 */
13
14#include "gk20a/gk20a.h"
15#include "clk.h"
16#include "clk_fll.h"
17#include "clk_domain.h"
18#include "include/bios.h"
19#include "boardobj/boardobjgrp.h"
20#include "boardobj/boardobjgrp_e32.h"
21#include "pmuif/gpmuifboardobj.h"
22#include "pmuif/gpmuifclk.h"
23#include "gm206/bios_gm206.h"
24#include "ctrl/ctrlclk.h"
25#include "ctrl/ctrlvolt.h"
26#include "gk20a/pmu_gk20a.h"
27
28static struct clk_domain *construct_clk_domain(struct gk20a *g, void *pargs);
29
30static u32 devinit_get_clocks_table(struct gk20a *g,
31 struct clk_domains *pdomainobjs);
32
33static u32 clk_domain_pmudatainit_super(struct gk20a *g, struct boardobj
34 *board_obj_ptr, struct nv_pmu_boardobj *ppmudata);
35
36const struct vbios_clocks_table_1x_hal_clock_entry vbiosclktbl1xhalentry[] = {
37 { clkwhich_gpc2clk, true, },
38 { clkwhich_xbar2clk, true, },
39 { clkwhich_mclk, false, },
40 { clkwhich_sys2clk, true, },
41 { clkwhich_hub2clk, false, },
42 { clkwhich_nvdclk, false, },
43 { clkwhich_pwrclk, false, },
44 { clkwhich_dispclk, false, },
45 { clkwhich_pciegenclk, false, }
46};
47
48static u32 clktranslatehalmumsettoapinumset(u32 clkhaldomains)
49{
50 u32 clkapidomains = 0;
51
52 if (clkhaldomains & BIT(clkwhich_gpc2clk))
53 clkapidomains |= CTRL_CLK_DOMAIN_GPC2CLK;
54 if (clkhaldomains & BIT(clkwhich_xbar2clk))
55 clkapidomains |= CTRL_CLK_DOMAIN_XBAR2CLK;
56 if (clkhaldomains & BIT(clkwhich_sys2clk))
57 clkapidomains |= CTRL_CLK_DOMAIN_SYS2CLK;
58 if (clkhaldomains & BIT(clkwhich_hub2clk))
59 clkapidomains |= CTRL_CLK_DOMAIN_HUB2CLK;
60 if (clkhaldomains & BIT(clkwhich_pwrclk))
61 clkapidomains |= CTRL_CLK_DOMAIN_PWRCLK;
62 if (clkhaldomains & BIT(clkwhich_pciegenclk))
63 clkapidomains |= CTRL_CLK_DOMAIN_PCIEGENCLK;
64 if (clkhaldomains & BIT(clkwhich_mclk))
65 clkapidomains |= CTRL_CLK_DOMAIN_MCLK;
66 if (clkhaldomains & BIT(clkwhich_nvdclk))
67 clkapidomains |= CTRL_CLK_DOMAIN_NVDCLK;
68 if (clkhaldomains & BIT(clkwhich_dispclk))
69 clkapidomains |= CTRL_CLK_DOMAIN_DISPCLK;
70
71 return clkapidomains;
72}
73
74static u32 _clk_domains_pmudatainit_3x(struct gk20a *g,
75 struct boardobjgrp *pboardobjgrp,
76 struct nv_pmu_boardobjgrp_super *pboardobjgrppmu)
77{
78 struct nv_pmu_clk_clk_domain_boardobjgrp_set_header *pset =
79 (struct nv_pmu_clk_clk_domain_boardobjgrp_set_header *)
80 pboardobjgrppmu;
81 struct clk_domains *pdomains = (struct clk_domains *)pboardobjgrp;
82 u32 status = 0;
83
84 status = boardobjgrp_pmudatainit_e32(g, pboardobjgrp, pboardobjgrppmu);
85 if (status) {
86 gk20a_err(dev_from_gk20a(g),
87 "error updating pmu boardobjgrp for clk domain 0x%x",
88 status);
89 goto done;
90 }
91
92 pset->vbios_domains = pdomains->vbios_domains;
93 pset->cntr_sampling_periodms = pdomains->cntr_sampling_periodms;
94 pset->b_override_o_v_o_c = false;
95 pset->b_debug_mode = false;
96 pset->b_enforce_vf_monotonicity = pdomains->b_enforce_vf_monotonicity;
97 pset->b_enforce_vf_smoothening = pdomains->b_enforce_vf_smoothening;
98 pset->volt_rails_max = 2;
99 status = boardobjgrpmask_export(
100 &pdomains->master_domains_mask.super,
101 pdomains->master_domains_mask.super.bitcount,
102 &pset->master_domains_mask.super);
103
104 memcpy(&pset->deltas, &pdomains->deltas,
105 (sizeof(struct ctrl_clk_clk_delta)));
106
107done:
108 return status;
109}
110
111static u32 _clk_domains_pmudata_instget(struct gk20a *g,
112 struct nv_pmu_boardobjgrp *pmuboardobjgrp,
113 struct nv_pmu_boardobj **ppboardobjpmudata,
114 u8 idx)
115{
116 struct nv_pmu_clk_clk_domain_boardobj_grp_set *pgrp_set =
117 (struct nv_pmu_clk_clk_domain_boardobj_grp_set *)
118 pmuboardobjgrp;
119
120 gk20a_dbg_info("");
121
122 /*check whether pmuboardobjgrp has a valid boardobj in index*/
123 if (((u32)BIT(idx) &
124 pgrp_set->hdr.data.super.obj_mask.super.data[0]) == 0)
125 return -EINVAL;
126
127 *ppboardobjpmudata = (struct nv_pmu_boardobj *)
128 &pgrp_set->objects[idx].data.board_obj;
129 gk20a_dbg_info(" Done");
130 return 0;
131}
132
133u32 clk_domain_sw_setup(struct gk20a *g)
134{
135 u32 status;
136 struct boardobjgrp *pboardobjgrp = NULL;
137 struct clk_domains *pclkdomainobjs;
138 struct clk_domain *pdomain;
139 struct clk_domain_3x_master *pdomain_master;
140 struct clk_domain_3x_slave *pdomain_slave;
141 u8 i;
142
143 gk20a_dbg_info("");
144
145 status = boardobjgrpconstruct_e32(&g->clk_pmu.clk_domainobjs.super);
146 if (status) {
147 gk20a_err(dev_from_gk20a(g),
148 "error creating boardobjgrp for clk domain, status - 0x%x",
149 status);
150 goto done;
151 }
152
153 pboardobjgrp = &g->clk_pmu.clk_domainobjs.super.super;
154 pclkdomainobjs = &(g->clk_pmu.clk_domainobjs);
155
156 BOARDOBJGRP_PMU_CONSTRUCT(pboardobjgrp, CLK, CLK_DOMAIN);
157
158 status = BOARDOBJGRP_PMU_CMD_GRP_SET_CONSTRUCT(g, pboardobjgrp,
159 clk, CLK, clk_domain, CLK_DOMAIN);
160 if (status) {
161 gk20a_err(dev_from_gk20a(g),
162 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
163 status);
164 goto done;
165 }
166
167 pboardobjgrp->pmudatainit = _clk_domains_pmudatainit_3x;
168 pboardobjgrp->pmudatainstget = _clk_domains_pmudata_instget;
169
170 /* Initialize mask to zero.*/
171 boardobjgrpmask_e32_init(&pclkdomainobjs->prog_domains_mask, NULL);
172 boardobjgrpmask_e32_init(&pclkdomainobjs->master_domains_mask, NULL);
173 pclkdomainobjs->b_enforce_vf_monotonicity = true;
174 pclkdomainobjs->b_enforce_vf_smoothening = true;
175
176 memset(&pclkdomainobjs->ordered_noise_aware_list, 0,
177 sizeof(pclkdomainobjs->ordered_noise_aware_list));
178
179 memset(&pclkdomainobjs->ordered_noise_unaware_list, 0,
180 sizeof(pclkdomainobjs->ordered_noise_unaware_list));
181
182 memset(&pclkdomainobjs->deltas, 0,
183 sizeof(struct ctrl_clk_clk_delta));
184
185 status = devinit_get_clocks_table(g, pclkdomainobjs);
186 if (status)
187 goto done;
188
189 BOARDOBJGRP_FOR_EACH(&(pclkdomainobjs->super.super),
190 struct clk_domain *, pdomain, i) {
191 pdomain_master = NULL;
192 if (pdomain->super.implements(g, &pdomain->super,
193 CTRL_CLK_CLK_DOMAIN_TYPE_3X_PROG)) {
194 status = boardobjgrpmask_bitset(
195 &pclkdomainobjs->prog_domains_mask.super, i);
196 if (status)
197 goto done;
198 }
199
200 if (pdomain->super.implements(g, &pdomain->super,
201 CTRL_CLK_CLK_DOMAIN_TYPE_3X_MASTER)) {
202 status = boardobjgrpmask_bitset(
203 &pclkdomainobjs->master_domains_mask.super, i);
204 if (status)
205 goto done;
206 }
207
208 if (pdomain->super.implements(g, &pdomain->super,
209 CTRL_CLK_CLK_DOMAIN_TYPE_3X_SLAVE)) {
210 pdomain_slave =
211 (struct clk_domain_3x_slave *)pdomain;
212 pdomain_master =
213 (struct clk_domain_3x_master *)
214 (CLK_CLK_DOMAIN_GET((&g->clk_pmu),
215 pdomain_slave->master_idx));
216 pdomain_master->slave_idxs_mask |= BIT(i);
217 }
218
219 }
220
221done:
222 gk20a_dbg_info(" done status %x", status);
223 return status;
224}
225
226u32 clk_domain_pmu_setup(struct gk20a *g)
227{
228 u32 status;
229 struct boardobjgrp *pboardobjgrp = NULL;
230
231 gk20a_dbg_info("");
232
233 pboardobjgrp = &g->clk_pmu.clk_domainobjs.super.super;
234
235 if (!pboardobjgrp->bconstructed)
236 return -EINVAL;
237
238 status = pboardobjgrp->pmuinithandle(g, pboardobjgrp);
239
240 gk20a_dbg_info("Done");
241 return status;
242}
243
244static u32 devinit_get_clocks_table(struct gk20a *g,
245 struct clk_domains *pclkdomainobjs)
246{
247 u32 status = 0;
248 u8 *clocks_table_ptr = NULL;
249 struct vbios_clocks_table_1x_header clocks_table_header = { 0 };
250 struct vbios_clocks_table_1x_entry clocks_table_entry = { 0 };
251 u8 *clocks_tbl_entry_ptr = NULL;
252 u32 index = 0;
253 struct clk_domain *pclkdomain_dev;
254 union {
255 struct boardobj boardobj;
256 struct clk_domain clk_domain;
257 struct clk_domain_3x v3x;
258 struct clk_domain_3x_fixed v3x_fixed;
259 struct clk_domain_3x_prog v3x_prog;
260 struct clk_domain_3x_master v3x_master;
261 struct clk_domain_3x_slave v3x_slave;
262 } clk_domain_data;
263
264 gk20a_dbg_info("");
265
266 if (g->ops.bios.get_perf_table_ptrs) {
267 clocks_table_ptr = (u8 *)g->ops.bios.get_perf_table_ptrs(g,
268 g->bios.clock_token, CLOCKS_TABLE);
269 if (clocks_table_ptr == NULL) {
270 status = -EINVAL;
271 goto done;
272 }
273 }
274
275 memcpy(&clocks_table_header, clocks_table_ptr,
276 VBIOS_CLOCKS_TABLE_1X_HEADER_SIZE_07);
277 if (clocks_table_header.header_size <
278 VBIOS_CLOCKS_TABLE_1X_HEADER_SIZE_07) {
279 status = -EINVAL;
280 goto done;
281 }
282
283 if (clocks_table_header.entry_size <
284 VBIOS_CLOCKS_TABLE_1X_ENTRY_SIZE_09) {
285 status = -EINVAL;
286 goto done;
287 }
288
289 pclkdomainobjs->cntr_sampling_periodms =
290 (u16)clocks_table_header.cntr_sampling_periodms;
291
292 /* Read table entries*/
293 clocks_tbl_entry_ptr = clocks_table_ptr +
294 VBIOS_CLOCKS_TABLE_1X_HEADER_SIZE_07;
295 for (index = 0; index < clocks_table_header.entry_count; index++) {
296 memcpy(&clocks_table_entry, clocks_tbl_entry_ptr,
297 clocks_table_header.entry_size);
298 clk_domain_data.clk_domain.domain =
299 vbiosclktbl1xhalentry[index].domain;
300 clk_domain_data.clk_domain.api_domain =
301 clktranslatehalmumsettoapinumset(
302 BIT(clk_domain_data.clk_domain.domain));
303 clk_domain_data.v3x.b_noise_aware_capable =
304 vbiosclktbl1xhalentry[index].b_noise_aware_capable;
305
306 switch (BIOS_GET_FIELD(clocks_table_entry.flags0,
307 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_FLAGS0_USAGE)) {
308 case NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_FLAGS0_USAGE_FIXED:
309 clk_domain_data.boardobj.type =
310 CTRL_CLK_CLK_DOMAIN_TYPE_3X_FIXED;
311 clk_domain_data.v3x_fixed.freq_mhz = (u16)BIOS_GET_FIELD(
312 clocks_table_entry.param1,
313 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM1_FIXED_FREQUENCY_MHZ);
314 break;
315
316 case NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_FLAGS0_USAGE_MASTER:
317 clk_domain_data.boardobj.type =
318 CTRL_CLK_CLK_DOMAIN_TYPE_3X_MASTER;
319 clk_domain_data.v3x_prog.clk_prog_idx_first =
320 (u8)(BIOS_GET_FIELD(clocks_table_entry.param0,
321 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM0_PROG_CLK_PROG_IDX_FIRST));
322 clk_domain_data.v3x_prog.clk_prog_idx_last =
323 (u8)(BIOS_GET_FIELD(clocks_table_entry.param0,
324 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM0_PROG_CLK_PROG_IDX_LAST));
325 clk_domain_data.v3x_prog.noise_unaware_ordering_index =
326 (u8)(BIOS_GET_FIELD(clocks_table_entry.param2,
327 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM2_PROG_NOISE_UNAWARE_ORDERING_IDX));
328
329 if (clk_domain_data.v3x.b_noise_aware_capable) {
330 clk_domain_data.v3x_prog.noise_aware_ordering_index =
331 (u8)(BIOS_GET_FIELD(clocks_table_entry.param2,
332 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM2_PROG_NOISE_AWARE_ORDERING_IDX));
333 clk_domain_data.v3x_prog.b_force_noise_unaware_ordering =
334 (u8)(BIOS_GET_FIELD(clocks_table_entry.param2,
335 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM2_PROG_FORCE_NOISE_UNAWARE_ORDERING));
336 } else {
337 clk_domain_data.v3x_prog.noise_aware_ordering_index =
338 CTRL_CLK_CLK_DOMAIN_3X_PROG_ORDERING_INDEX_INVALID;
339 clk_domain_data.v3x_prog.b_force_noise_unaware_ordering = false;
340 }
341 clk_domain_data.v3x_prog.factory_offset_khz = 0;
342
343 clk_domain_data.v3x_prog.freq_delta_min_mhz =
344 (u16)(BIOS_GET_FIELD(clocks_table_entry.param1,
345 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM1_MASTER_FREQ_OC_DELTA_MIN_MHZ));
346
347 clk_domain_data.v3x_prog.freq_delta_max_mhz =
348 (u16)(BIOS_GET_FIELD(clocks_table_entry.param1,
349 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM1_MASTER_FREQ_OC_DELTA_MAX_MHZ));
350 break;
351
352 case NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_FLAGS0_USAGE_SLAVE:
353 clk_domain_data.boardobj.type =
354 CTRL_CLK_CLK_DOMAIN_TYPE_3X_SLAVE;
355 clk_domain_data.v3x_prog.clk_prog_idx_first =
356 (u8)(BIOS_GET_FIELD(clocks_table_entry.param0,
357 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM0_PROG_CLK_PROG_IDX_FIRST));
358 clk_domain_data.v3x_prog.clk_prog_idx_last =
359 (u8)(BIOS_GET_FIELD(clocks_table_entry.param0,
360 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM0_PROG_CLK_PROG_IDX_LAST));
361 clk_domain_data.v3x_prog.noise_unaware_ordering_index =
362 (u8)(BIOS_GET_FIELD(clocks_table_entry.param2,
363 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM2_PROG_NOISE_UNAWARE_ORDERING_IDX));
364
365 if (clk_domain_data.v3x.b_noise_aware_capable) {
366 clk_domain_data.v3x_prog.noise_aware_ordering_index =
367 (u8)(BIOS_GET_FIELD(clocks_table_entry.param2,
368 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM2_PROG_NOISE_AWARE_ORDERING_IDX));
369 clk_domain_data.v3x_prog.b_force_noise_unaware_ordering =
370 (u8)(BIOS_GET_FIELD(clocks_table_entry.param2,
371 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM2_PROG_FORCE_NOISE_UNAWARE_ORDERING));
372 } else {
373 clk_domain_data.v3x_prog.noise_aware_ordering_index =
374 CTRL_CLK_CLK_DOMAIN_3X_PROG_ORDERING_INDEX_INVALID;
375 clk_domain_data.v3x_prog.b_force_noise_unaware_ordering = false;
376 }
377 clk_domain_data.v3x_prog.factory_offset_khz = 0;
378 clk_domain_data.v3x_prog.freq_delta_min_mhz = 0;
379 clk_domain_data.v3x_prog.freq_delta_max_mhz = 0;
380 clk_domain_data.v3x_slave.master_idx =
381 (u8)(BIOS_GET_FIELD(clocks_table_entry.param1,
382 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM1_SLAVE_MASTER_DOMAIN));
383 break;
384
385 default:
386 gk20a_err(dev_from_gk20a(g),
387 "error reading clock domain entry %d", index);
388 status = -EINVAL;
389 goto done;
390
391 }
392 pclkdomain_dev = construct_clk_domain(g,
393 (void *)&clk_domain_data);
394 if (pclkdomain_dev == NULL) {
395 gk20a_err(dev_from_gk20a(g),
396 "unable to construct clock domain boardobj for %d",
397 index);
398 status = -EINVAL;
399 goto done;
400 }
401 status = boardobjgrp_objinsert(&pclkdomainobjs->super.super,
402 (struct boardobj *)pclkdomain_dev, index);
403 if (status) {
404 gk20a_err(dev_from_gk20a(g),
405 "unable to insert clock domain boardobj for %d", index);
406 status = -EINVAL;
407 goto done;
408 }
409 clocks_tbl_entry_ptr += clocks_table_header.entry_size;
410 }
411
412done:
413 gk20a_dbg_info(" done status %x", status);
414 return status;
415}
416
417static u32 clkdomainclkproglink_not_supported(struct gk20a *g,
418 struct clk_pmupstate *pclk,
419 struct clk_domain *pdomain)
420{
421 gk20a_dbg_info("");
422 return -EINVAL;
423}
424
425static int clkdomainvfsearch_stub(
426 struct gk20a *g,
427 struct clk_pmupstate *pclk,
428 struct clk_domain *pdomain,
429 u16 *clkmhz,
430 u32 *voltuv,
431 u8 rail)
432
433{
434 gk20a_dbg_info("");
435 return -EINVAL;
436}
437
438static u32 clkdomaingetfpoints_stub(
439 struct gk20a *g,
440 struct clk_pmupstate *pclk,
441 struct clk_domain *pdomain,
442 u32 *pfpointscount,
443 u16 *pfreqpointsinmhz,
444 u8 rail)
445{
446 gk20a_dbg_info("");
447 return -EINVAL;
448}
449
450
451static u32 clk_domain_construct_super(struct gk20a *g,
452 struct boardobj **ppboardobj,
453 u16 size, void *pargs)
454{
455 struct clk_domain *pdomain;
456 struct clk_domain *ptmpdomain = (struct clk_domain *)pargs;
457 u32 status = 0;
458
459 status = boardobj_construct_super(g, ppboardobj,
460 size, pargs);
461
462 if (status)
463 return -EINVAL;
464
465 pdomain = (struct clk_domain *)*ppboardobj;
466
467 pdomain->super.pmudatainit =
468 clk_domain_pmudatainit_super;
469
470 pdomain->clkdomainclkproglink =
471 clkdomainclkproglink_not_supported;
472
473 pdomain->clkdomainclkvfsearch =
474 clkdomainvfsearch_stub;
475
476 pdomain->clkdomainclkgetfpoints =
477 clkdomaingetfpoints_stub;
478
479 pdomain->api_domain = ptmpdomain->api_domain;
480 pdomain->domain = ptmpdomain->domain;
481 pdomain->perf_domain_grp_idx =
482 ptmpdomain->perf_domain_grp_idx;
483
484 return status;
485}
486
487static u32 _clk_domain_pmudatainit_3x(struct gk20a *g,
488 struct boardobj *board_obj_ptr,
489 struct nv_pmu_boardobj *ppmudata)
490{
491 u32 status = 0;
492 struct clk_domain_3x *pclk_domain_3x;
493 struct nv_pmu_clk_clk_domain_3x_boardobj_set *pset;
494
495 gk20a_dbg_info("");
496
497 status = clk_domain_pmudatainit_super(g, board_obj_ptr, ppmudata);
498 if (status != 0)
499 return status;
500
501 pclk_domain_3x = (struct clk_domain_3x *)board_obj_ptr;
502
503 pset = (struct nv_pmu_clk_clk_domain_3x_boardobj_set *)ppmudata;
504
505 pset->b_noise_aware_capable = pclk_domain_3x->b_noise_aware_capable;
506
507 return status;
508}
509
510static u32 clk_domain_construct_3x(struct gk20a *g,
511 struct boardobj **ppboardobj,
512 u16 size, void *pargs)
513{
514 struct boardobj *ptmpobj = (struct boardobj *)pargs;
515 struct clk_domain_3x *pdomain;
516 struct clk_domain_3x *ptmpdomain =
517 (struct clk_domain_3x *)pargs;
518 u32 status = 0;
519
520 ptmpobj->type_mask = BIT(CTRL_CLK_CLK_DOMAIN_TYPE_3X);
521 status = clk_domain_construct_super(g, ppboardobj,
522 size, pargs);
523 if (status)
524 return -EINVAL;
525
526 pdomain = (struct clk_domain_3x *)*ppboardobj;
527
528 pdomain->super.super.pmudatainit =
529 _clk_domain_pmudatainit_3x;
530
531 pdomain->b_noise_aware_capable = ptmpdomain->b_noise_aware_capable;
532
533 return status;
534}
535
536static u32 clkdomainclkproglink_3x_prog(struct gk20a *g,
537 struct clk_pmupstate *pclk,
538 struct clk_domain *pdomain)
539{
540 u32 status = 0;
541 struct clk_domain_3x_prog *p3xprog =
542 (struct clk_domain_3x_prog *)pdomain;
543 struct clk_prog *pprog = NULL;
544 u8 i;
545
546 gk20a_dbg_info("");
547
548 for (i = p3xprog->clk_prog_idx_first;
549 i <= p3xprog->clk_prog_idx_last;
550 i++) {
551 pprog = CLK_CLK_PROG_GET(pclk, i);
552 if (pprog == NULL)
553 status = -EINVAL;
554 }
555 return status;
556}
557
558static int clkdomaingetslaveclk(struct gk20a *g,
559 struct clk_pmupstate *pclk,
560 struct clk_domain *pdomain,
561 u16 *pclkmhz,
562 u16 masterclkmhz)
563{
564 int status = 0;
565 struct clk_prog *pprog = NULL;
566 struct clk_prog_1x_master *pprog1xmaster = NULL;
567 u8 slaveidx;
568 struct clk_domain_3x_master *p3xmaster;
569
570 gk20a_dbg_info("");
571
572 if (pclkmhz == NULL)
573 return -EINVAL;
574
575 if (masterclkmhz == 0)
576 return -EINVAL;
577
578 slaveidx = BOARDOBJ_GET_IDX(pdomain);
579 p3xmaster = (struct clk_domain_3x_master *)
580 CLK_CLK_DOMAIN_GET(pclk,
581 ((struct clk_domain_3x_slave *)
582 pdomain)->master_idx);
583 pprog = CLK_CLK_PROG_GET(pclk, p3xmaster->super.clk_prog_idx_first);
584 pprog1xmaster = (struct clk_prog_1x_master *)pprog;
585
586 status = pprog1xmaster->getslaveclk(g, pclk, pprog1xmaster,
587 slaveidx, pclkmhz, masterclkmhz);
588 return status;
589}
590
591static int clkdomainvfsearch(struct gk20a *g,
592 struct clk_pmupstate *pclk,
593 struct clk_domain *pdomain,
594 u16 *pclkmhz,
595 u32 *pvoltuv,
596 u8 rail)
597{
598 int status = 0;
599 struct clk_domain_3x_master *p3xmaster =
600 (struct clk_domain_3x_master *)pdomain;
601 struct clk_prog *pprog = NULL;
602 struct clk_prog_1x_master *pprog1xmaster = NULL;
603 u8 i;
604 u8 *pslaveidx = NULL;
605 u8 slaveidx;
606 u16 clkmhz;
607 u32 voltuv;
608 u16 bestclkmhz;
609 u32 bestvoltuv;
610
611 gk20a_dbg_info("");
612
613 if ((pclkmhz == NULL) || (pvoltuv == NULL))
614 return -EINVAL;
615
616 if ((*pclkmhz != 0) && (*pvoltuv != 0))
617 return -EINVAL;
618
619 bestclkmhz = *pclkmhz;
620 bestvoltuv = *pvoltuv;
621
622 if (pdomain->super.implements(g, &pdomain->super,
623 CTRL_CLK_CLK_DOMAIN_TYPE_3X_SLAVE)) {
624 slaveidx = BOARDOBJ_GET_IDX(pdomain);
625 pslaveidx = &slaveidx;
626 p3xmaster = (struct clk_domain_3x_master *)
627 CLK_CLK_DOMAIN_GET(pclk,
628 ((struct clk_domain_3x_slave *)
629 pdomain)->master_idx);
630 }
631 /* Iterate over the set of CLK_PROGs pointed at by this domain.*/
632 for (i = p3xmaster->super.clk_prog_idx_first;
633 i <= p3xmaster->super.clk_prog_idx_last;
634 i++) {
635 clkmhz = *pclkmhz;
636 voltuv = *pvoltuv;
637 pprog = CLK_CLK_PROG_GET(pclk, i);
638
639 /* MASTER CLK_DOMAINs must point to MASTER CLK_PROGs.*/
640 if (!pprog->super.implements(g, &pprog->super,
641 CTRL_CLK_CLK_PROG_TYPE_1X_MASTER)) {
642 status = -EINVAL;
643 goto done;
644 }
645
646 pprog1xmaster = (struct clk_prog_1x_master *)pprog;
647 status = pprog1xmaster->vflookup(g, pclk, pprog1xmaster,
648 pslaveidx, &clkmhz, &voltuv, rail);
649 /* if look up has found the V or F value matching to other
650 exit */
651 if (status == 0) {
652 if (*pclkmhz == 0) {
653 bestclkmhz = clkmhz;
654 } else {
655 bestvoltuv = voltuv;
656 break;
657 }
658 }
659 }
660 /* clk and volt sent as zero to print vf table */
661 if ((*pclkmhz == 0) && (*pvoltuv == 0)) {
662 status = 0;
663 goto done;
664 }
665 /* atleast one search found a matching value? */
666 if ((bestvoltuv != 0) && (bestclkmhz != 0)) {
667 *pclkmhz = bestclkmhz;
668 *pvoltuv = bestvoltuv;
669 status = 0;
670 goto done;
671 }
672done:
673 gk20a_dbg_info("done status %x", status);
674 return status;
675}
676
677static u32 clkdomaingetfpoints
678(
679 struct gk20a *g,
680 struct clk_pmupstate *pclk,
681 struct clk_domain *pdomain,
682 u32 *pfpointscount,
683 u16 *pfreqpointsinmhz,
684 u8 rail
685)
686{
687 u32 status = 0;
688 struct clk_domain_3x_master *p3xmaster =
689 (struct clk_domain_3x_master *)pdomain;
690 struct clk_prog *pprog = NULL;
691 struct clk_prog_1x_master *pprog1xmaster = NULL;
692 u32 fpointscount = 0;
693 u32 remainingcount;
694 u32 totalcount;
695 u16 *freqpointsdata;
696 u8 i;
697
698 gk20a_dbg_info("");
699
700 if (pfpointscount == NULL)
701 return -EINVAL;
702
703 if ((pfreqpointsinmhz == NULL) && (*pfpointscount != 0))
704 return -EINVAL;
705
706 if (pdomain->super.implements(g, &pdomain->super,
707 CTRL_CLK_CLK_DOMAIN_TYPE_3X_SLAVE))
708 return -EINVAL;
709
710 freqpointsdata = pfreqpointsinmhz;
711 totalcount = 0;
712 fpointscount = *pfpointscount;
713 remainingcount = fpointscount;
714 /* Iterate over the set of CLK_PROGs pointed at by this domain.*/
715 for (i = p3xmaster->super.clk_prog_idx_first;
716 i <= p3xmaster->super.clk_prog_idx_last;
717 i++) {
718 pprog = CLK_CLK_PROG_GET(pclk, i);
719 pprog1xmaster = (struct clk_prog_1x_master *)pprog;
720 status = pprog1xmaster->getfpoints(g, pclk, pprog1xmaster,
721 &fpointscount, &freqpointsdata, rail);
722 if (status) {
723 *pfpointscount = 0;
724 goto done;
725 }
726 totalcount += fpointscount;
727 if (*pfpointscount) {
728 remainingcount -= fpointscount;
729 fpointscount = remainingcount;
730 } else
731 fpointscount = 0;
732
733 }
734
735 *pfpointscount = totalcount;
736done:
737 gk20a_dbg_info("done status %x", status);
738 return status;
739}
740
741static u32 _clk_domain_pmudatainit_3x_prog(struct gk20a *g,
742 struct boardobj *board_obj_ptr,
743 struct nv_pmu_boardobj *ppmudata)
744{
745 u32 status = 0;
746 struct clk_domain_3x_prog *pclk_domain_3x_prog;
747 struct nv_pmu_clk_clk_domain_3x_prog_boardobj_set *pset;
748 struct clk_domains *pdomains = &(g->clk_pmu.clk_domainobjs);
749
750 gk20a_dbg_info("");
751
752 status = _clk_domain_pmudatainit_3x(g, board_obj_ptr, ppmudata);
753 if (status != 0)
754 return status;
755
756 pclk_domain_3x_prog = (struct clk_domain_3x_prog *)board_obj_ptr;
757
758 pset = (struct nv_pmu_clk_clk_domain_3x_prog_boardobj_set *)
759 ppmudata;
760
761 pset->clk_prog_idx_first = pclk_domain_3x_prog->clk_prog_idx_first;
762 pset->clk_prog_idx_last = pclk_domain_3x_prog->clk_prog_idx_last;
763 pset->noise_unaware_ordering_index =
764 pclk_domain_3x_prog->noise_unaware_ordering_index;
765 pset->noise_aware_ordering_index =
766 pclk_domain_3x_prog->noise_aware_ordering_index;
767 pset->b_force_noise_unaware_ordering =
768 pclk_domain_3x_prog->b_force_noise_unaware_ordering;
769 pset->factory_offset_khz = pclk_domain_3x_prog->factory_offset_khz;
770 pset->freq_delta_min_mhz = pclk_domain_3x_prog->freq_delta_min_mhz;
771 pset->freq_delta_max_mhz = pclk_domain_3x_prog->freq_delta_max_mhz;
772 memcpy(&pset->deltas, &pdomains->deltas,
773 (sizeof(struct ctrl_clk_clk_delta)));
774
775 return status;
776}
777
778static u32 clk_domain_construct_3x_prog(struct gk20a *g,
779 struct boardobj **ppboardobj,
780 u16 size, void *pargs)
781{
782 struct boardobj *ptmpobj = (struct boardobj *)pargs;
783 struct clk_domain_3x_prog *pdomain;
784 struct clk_domain_3x_prog *ptmpdomain =
785 (struct clk_domain_3x_prog *)pargs;
786 u32 status = 0;
787
788 ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_DOMAIN_TYPE_3X_PROG);
789 status = clk_domain_construct_3x(g, ppboardobj, size, pargs);
790 if (status)
791 return -EINVAL;
792
793 pdomain = (struct clk_domain_3x_prog *)*ppboardobj;
794
795 pdomain->super.super.super.pmudatainit =
796 _clk_domain_pmudatainit_3x_prog;
797
798 pdomain->super.super.clkdomainclkproglink =
799 clkdomainclkproglink_3x_prog;
800
801 pdomain->super.super.clkdomainclkvfsearch =
802 clkdomainvfsearch;
803
804 pdomain->super.super.clkdomainclkgetfpoints =
805 clkdomaingetfpoints;
806
807 pdomain->clk_prog_idx_first = ptmpdomain->clk_prog_idx_first;
808 pdomain->clk_prog_idx_last = ptmpdomain->clk_prog_idx_last;
809 pdomain->noise_unaware_ordering_index =
810 ptmpdomain->noise_unaware_ordering_index;
811 pdomain->noise_aware_ordering_index =
812 ptmpdomain->noise_aware_ordering_index;
813 pdomain->b_force_noise_unaware_ordering =
814 ptmpdomain->b_force_noise_unaware_ordering;
815 pdomain->factory_offset_khz = ptmpdomain->factory_offset_khz;
816 pdomain->freq_delta_min_mhz = ptmpdomain->freq_delta_min_mhz;
817 pdomain->freq_delta_max_mhz = ptmpdomain->freq_delta_max_mhz;
818
819 return status;
820}
821
822static u32 _clk_domain_pmudatainit_3x_slave(struct gk20a *g,
823 struct boardobj *board_obj_ptr,
824 struct nv_pmu_boardobj *ppmudata)
825{
826 u32 status = 0;
827 struct clk_domain_3x_slave *pclk_domain_3x_slave;
828 struct nv_pmu_clk_clk_domain_3x_slave_boardobj_set *pset;
829
830 gk20a_dbg_info("");
831
832 status = _clk_domain_pmudatainit_3x_prog(g, board_obj_ptr, ppmudata);
833 if (status != 0)
834 return status;
835
836 pclk_domain_3x_slave = (struct clk_domain_3x_slave *)board_obj_ptr;
837
838 pset = (struct nv_pmu_clk_clk_domain_3x_slave_boardobj_set *)
839 ppmudata;
840
841 pset->master_idx = pclk_domain_3x_slave->master_idx;
842
843 return status;
844}
845
846static u32 clk_domain_construct_3x_slave(struct gk20a *g,
847 struct boardobj **ppboardobj,
848 u16 size, void *pargs)
849{
850 struct boardobj *ptmpobj = (struct boardobj *)pargs;
851 struct clk_domain_3x_slave *pdomain;
852 struct clk_domain_3x_slave *ptmpdomain =
853 (struct clk_domain_3x_slave *)pargs;
854 u32 status = 0;
855
856 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_CLK_CLK_DOMAIN_TYPE_3X_SLAVE)
857 return -EINVAL;
858
859 ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_DOMAIN_TYPE_3X_SLAVE);
860 status = clk_domain_construct_3x_prog(g, ppboardobj, size, pargs);
861 if (status)
862 return -EINVAL;
863
864 pdomain = (struct clk_domain_3x_slave *)*ppboardobj;
865
866 pdomain->super.super.super.super.pmudatainit =
867 _clk_domain_pmudatainit_3x_slave;
868
869 pdomain->master_idx = ptmpdomain->master_idx;
870
871 pdomain->clkdomainclkgetslaveclk =
872 clkdomaingetslaveclk;
873
874 return status;
875}
876
877static u32 clkdomainclkproglink_3x_master(struct gk20a *g,
878 struct clk_pmupstate *pclk,
879 struct clk_domain *pdomain)
880{
881 u32 status = 0;
882 struct clk_domain_3x_master *p3xmaster =
883 (struct clk_domain_3x_master *)pdomain;
884 struct clk_prog *pprog = NULL;
885 struct clk_prog_1x_master *pprog1xmaster = NULL;
886 u16 freq_max_last_mhz = 0;
887 u8 i;
888
889 gk20a_dbg_info("");
890
891 status = clkdomainclkproglink_3x_prog(g, pclk, pdomain);
892 if (status)
893 goto done;
894
895 /* Iterate over the set of CLK_PROGs pointed at by this domain.*/
896 for (i = p3xmaster->super.clk_prog_idx_first;
897 i <= p3xmaster->super.clk_prog_idx_last;
898 i++) {
899 pprog = CLK_CLK_PROG_GET(pclk, i);
900
901 /* MASTER CLK_DOMAINs must point to MASTER CLK_PROGs.*/
902 if (!pprog->super.implements(g, &pprog->super,
903 CTRL_CLK_CLK_PROG_TYPE_1X_MASTER)) {
904 status = -EINVAL;
905 goto done;
906 }
907
908 pprog1xmaster = (struct clk_prog_1x_master *)pprog;
909 status = pprog1xmaster->vfflatten(g, pclk, pprog1xmaster,
910 BOARDOBJ_GET_IDX(p3xmaster), &freq_max_last_mhz);
911 if (status)
912 goto done;
913 }
914done:
915 gk20a_dbg_info("done status %x", status);
916 return status;
917}
918
919static u32 _clk_domain_pmudatainit_3x_master(struct gk20a *g,
920 struct boardobj *board_obj_ptr,
921 struct nv_pmu_boardobj *ppmudata)
922{
923 u32 status = 0;
924 struct clk_domain_3x_master *pclk_domain_3x_master;
925 struct nv_pmu_clk_clk_domain_3x_master_boardobj_set *pset;
926
927 gk20a_dbg_info("");
928
929 status = _clk_domain_pmudatainit_3x_prog(g, board_obj_ptr, ppmudata);
930 if (status != 0)
931 return status;
932
933 pclk_domain_3x_master = (struct clk_domain_3x_master *)board_obj_ptr;
934
935 pset = (struct nv_pmu_clk_clk_domain_3x_master_boardobj_set *)
936 ppmudata;
937
938 pset->slave_idxs_mask = pclk_domain_3x_master->slave_idxs_mask;
939
940 return status;
941}
942
943static u32 clk_domain_construct_3x_master(struct gk20a *g,
944 struct boardobj **ppboardobj,
945 u16 size, void *pargs)
946{
947 struct boardobj *ptmpobj = (struct boardobj *)pargs;
948 struct clk_domain_3x_master *pdomain;
949 u32 status = 0;
950
951 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_CLK_CLK_DOMAIN_TYPE_3X_MASTER)
952 return -EINVAL;
953
954 ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_DOMAIN_TYPE_3X_MASTER);
955 status = clk_domain_construct_3x_prog(g, ppboardobj, size, pargs);
956 if (status)
957 return -EINVAL;
958
959 pdomain = (struct clk_domain_3x_master *)*ppboardobj;
960
961 pdomain->super.super.super.super.pmudatainit =
962 _clk_domain_pmudatainit_3x_master;
963 pdomain->super.super.super.clkdomainclkproglink =
964 clkdomainclkproglink_3x_master;
965
966 pdomain->slave_idxs_mask = 0;
967
968 return status;
969}
970
971static u32 clkdomainclkproglink_fixed(struct gk20a *g,
972 struct clk_pmupstate *pclk,
973 struct clk_domain *pdomain)
974{
975 gk20a_dbg_info("");
976 return 0;
977}
978
979static u32 _clk_domain_pmudatainit_3x_fixed(struct gk20a *g,
980 struct boardobj *board_obj_ptr,
981 struct nv_pmu_boardobj *ppmudata)
982{
983 u32 status = 0;
984 struct clk_domain_3x_fixed *pclk_domain_3x_fixed;
985 struct nv_pmu_clk_clk_domain_3x_fixed_boardobj_set *pset;
986
987 gk20a_dbg_info("");
988
989 status = _clk_domain_pmudatainit_3x(g, board_obj_ptr, ppmudata);
990 if (status != 0)
991 return status;
992
993 pclk_domain_3x_fixed = (struct clk_domain_3x_fixed *)board_obj_ptr;
994
995 pset = (struct nv_pmu_clk_clk_domain_3x_fixed_boardobj_set *)
996 ppmudata;
997
998 pset->freq_mhz = pclk_domain_3x_fixed->freq_mhz;
999
1000 return status;
1001}
1002
1003static u32 clk_domain_construct_3x_fixed(struct gk20a *g,
1004 struct boardobj **ppboardobj,
1005 u16 size, void *pargs)
1006{
1007 struct boardobj *ptmpobj = (struct boardobj *)pargs;
1008 struct clk_domain_3x_fixed *pdomain;
1009 struct clk_domain_3x_fixed *ptmpdomain =
1010 (struct clk_domain_3x_fixed *)pargs;
1011 u32 status = 0;
1012
1013 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_CLK_CLK_DOMAIN_TYPE_3X_FIXED)
1014 return -EINVAL;
1015
1016 ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_DOMAIN_TYPE_3X_FIXED);
1017 status = clk_domain_construct_3x(g, ppboardobj, size, pargs);
1018 if (status)
1019 return -EINVAL;
1020
1021 pdomain = (struct clk_domain_3x_fixed *)*ppboardobj;
1022
1023 pdomain->super.super.super.pmudatainit =
1024 _clk_domain_pmudatainit_3x_fixed;
1025
1026 pdomain->super.super.clkdomainclkproglink =
1027 clkdomainclkproglink_fixed;
1028
1029 pdomain->freq_mhz = ptmpdomain->freq_mhz;
1030
1031 return status;
1032}
1033
1034static struct clk_domain *construct_clk_domain(struct gk20a *g, void *pargs)
1035{
1036 struct boardobj *board_obj_ptr = NULL;
1037 u32 status;
1038
1039 gk20a_dbg_info(" %d", BOARDOBJ_GET_TYPE(pargs));
1040 switch (BOARDOBJ_GET_TYPE(pargs)) {
1041 case CTRL_CLK_CLK_DOMAIN_TYPE_3X_FIXED:
1042 status = clk_domain_construct_3x_fixed(g, &board_obj_ptr,
1043 sizeof(struct clk_domain_3x_fixed), pargs);
1044 break;
1045
1046 case CTRL_CLK_CLK_DOMAIN_TYPE_3X_MASTER:
1047 status = clk_domain_construct_3x_master(g, &board_obj_ptr,
1048 sizeof(struct clk_domain_3x_master), pargs);
1049 break;
1050
1051 case CTRL_CLK_CLK_DOMAIN_TYPE_3X_SLAVE:
1052 status = clk_domain_construct_3x_slave(g, &board_obj_ptr,
1053 sizeof(struct clk_domain_3x_slave), pargs);
1054 break;
1055
1056 default:
1057 return NULL;
1058 }
1059
1060 if (status)
1061 return NULL;
1062
1063 gk20a_dbg_info(" Done");
1064
1065 return (struct clk_domain *)board_obj_ptr;
1066}
1067
1068static u32 clk_domain_pmudatainit_super(struct gk20a *g,
1069 struct boardobj *board_obj_ptr,
1070 struct nv_pmu_boardobj *ppmudata)
1071{
1072 u32 status = 0;
1073 struct clk_domain *pclk_domain;
1074 struct nv_pmu_clk_clk_domain_boardobj_set *pset;
1075
1076 gk20a_dbg_info("");
1077
1078 status = boardobj_pmudatainit_super(g, board_obj_ptr, ppmudata);
1079 if (status != 0)
1080 return status;
1081
1082 pclk_domain = (struct clk_domain *)board_obj_ptr;
1083
1084 pset = (struct nv_pmu_clk_clk_domain_boardobj_set *)ppmudata;
1085
1086 pset->domain = pclk_domain->domain;
1087 pset->api_domain = pclk_domain->api_domain;
1088 pset->perf_domain_grp_idx = pclk_domain->perf_domain_grp_idx;
1089
1090 return status;
1091}
1092
1093u32 clk_domain_clk_prog_link(struct gk20a *g, struct clk_pmupstate *pclk)
1094{
1095 u32 status = 0;
1096 struct clk_domain *pdomain;
1097 u8 i;
1098
1099 /* Iterate over all CLK_DOMAINs and flatten their VF curves.*/
1100 BOARDOBJGRP_FOR_EACH(&(pclk->clk_domainobjs.super.super),
1101 struct clk_domain *, pdomain, i) {
1102 status = pdomain->clkdomainclkproglink(g, pclk, pdomain);
1103 if (status) {
1104 gk20a_err(dev_from_gk20a(g),
1105 "error flattening VF for CLK DOMAIN - 0x%x",
1106 pdomain->domain);
1107 goto done;
1108 }
1109 }
1110
1111done:
1112 return status;
1113}
diff --git a/drivers/gpu/nvgpu/clk/clk_domain.h b/drivers/gpu/nvgpu/clk/clk_domain.h
new file mode 100644
index 00000000..443e1c4c
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk_domain.h
@@ -0,0 +1,116 @@
1/*
2* Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
3*
4* This program is free software; you can redistribute it and/or modify it
5* under the terms and conditions of the GNU General Public License,
6* version 2, as published by the Free Software Foundation.
7*
8* This program is distributed in the hope it will be useful, but WITHOUT
9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11* more details.
12*/
13
14#ifndef _CLKDOMAIN_H_
15#define _CLKDOMAIN_H_
16
17#include "ctrl/ctrlclk.h"
18#include "ctrl/ctrlboardobj.h"
19#include "pmuif/gpmuifclk.h"
20#include "boardobj/boardobjgrp_e32.h"
21#include "boardobj/boardobjgrpmask.h"
22
23struct clk_domains;
24struct clk_domain;
25
26/*data and function definition to talk to driver*/
27u32 clk_domain_sw_setup(struct gk20a *g);
28u32 clk_domain_pmu_setup(struct gk20a *g);
29
30typedef u32 clkproglink(struct gk20a *g, struct clk_pmupstate *pclk,
31 struct clk_domain *pdomain);
32
33typedef int clkvfsearch(struct gk20a *g, struct clk_pmupstate *pclk,
34 struct clk_domain *pdomain, u16 *clkmhz,
35 u32 *voltuv, u8 rail);
36
37typedef int clkgetslaveclk(struct gk20a *g, struct clk_pmupstate *pclk,
38 struct clk_domain *pdomain, u16 *clkmhz,
39 u16 masterclkmhz);
40
41typedef u32 clkgetfpoints(struct gk20a *g, struct clk_pmupstate *pclk,
42 struct clk_domain *pdomain, u32 *pfpointscount,
43 u16 *pfreqpointsinmhz, u8 rail);
44
45struct clk_domains {
46 struct boardobjgrp_e32 super;
47 u8 n_num_entries;
48 u8 version;
49 bool b_enforce_vf_monotonicity;
50 bool b_enforce_vf_smoothening;
51 u32 vbios_domains;
52 struct boardobjgrpmask_e32 prog_domains_mask;
53 struct boardobjgrpmask_e32 master_domains_mask;
54 u16 cntr_sampling_periodms;
55 struct ctrl_clk_clk_delta deltas;
56
57 struct clk_domain *ordered_noise_aware_list[CTRL_BOARDOBJ_MAX_BOARD_OBJECTS];
58
59 struct clk_domain *ordered_noise_unaware_list[CTRL_BOARDOBJ_MAX_BOARD_OBJECTS];
60};
61
62struct clk_domain {
63 struct boardobj super;
64 u32 api_domain;
65 u32 part_mask;
66 u8 domain;
67 u8 perf_domain_index;
68 u8 perf_domain_grp_idx;
69 u8 ratio_domain;
70 u8 usage;
71 clkproglink *clkdomainclkproglink;
72 clkvfsearch *clkdomainclkvfsearch;
73 clkgetfpoints *clkdomainclkgetfpoints;
74};
75
76struct clk_domain_3x {
77 struct clk_domain super;
78 bool b_noise_aware_capable;
79};
80
81struct clk_domain_3x_fixed {
82 struct clk_domain_3x super;
83 u16 freq_mhz;
84};
85
86struct clk_domain_3x_prog {
87 struct clk_domain_3x super;
88 u8 clk_prog_idx_first;
89 u8 clk_prog_idx_last;
90 u8 noise_unaware_ordering_index;
91 u8 noise_aware_ordering_index;
92 bool b_force_noise_unaware_ordering;
93 int factory_offset_khz;
94 short freq_delta_min_mhz;
95 short freq_delta_max_mhz;
96 struct ctrl_clk_clk_delta deltas;
97};
98
99struct clk_domain_3x_master {
100 struct clk_domain_3x_prog super;
101 u32 slave_idxs_mask;
102};
103
104struct clk_domain_3x_slave {
105 struct clk_domain_3x_prog super;
106 u8 master_idx;
107 clkgetslaveclk *clkdomainclkgetslaveclk;
108};
109
110u32 clk_domain_clk_prog_link(struct gk20a *g, struct clk_pmupstate *pclk);
111
112#define CLK_CLK_DOMAIN_GET(pclk, idx) \
113 ((struct clk_domain *)BOARDOBJGRP_OBJ_GET_BY_IDX( \
114 &pclk->clk_domainobjs.super.super, (u8)(idx)))
115
116#endif
diff --git a/drivers/gpu/nvgpu/clk/clk_fll.c b/drivers/gpu/nvgpu/clk/clk_fll.c
new file mode 100644
index 00000000..0de857f5
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk_fll.c
@@ -0,0 +1,440 @@
1/*
2 * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 */
13
14#include "gk20a/gk20a.h"
15#include "clk.h"
16#include "clk_fll.h"
17#include "include/bios.h"
18#include "boardobj/boardobjgrp.h"
19#include "boardobj/boardobjgrp_e32.h"
20#include "pmuif/gpmuifboardobj.h"
21#include "pmuif/gpmuifclk.h"
22#include "gm206/bios_gm206.h"
23#include "ctrl/ctrlclk.h"
24#include "ctrl/ctrlvolt.h"
25#include "gk20a/pmu_gk20a.h"
26
27static u32 devinit_get_fll_device_table(struct gk20a *g,
28 struct avfsfllobjs *pfllobjs);
29static struct fll_device *construct_fll_device(struct gk20a *g,
30 void *pargs);
31static u32 fll_device_init_pmudata_super(struct gk20a *g,
32 struct boardobj *board_obj_ptr,
33 struct nv_pmu_boardobj *ppmudata);
34
35static u32 _clk_fll_devgrp_pmudatainit_super(struct gk20a *g,
36 struct boardobjgrp *pboardobjgrp,
37 struct nv_pmu_boardobjgrp_super *pboardobjgrppmu)
38{
39 struct nv_pmu_clk_clk_fll_device_boardobjgrp_set_header *pset =
40 (struct nv_pmu_clk_clk_fll_device_boardobjgrp_set_header *)
41 pboardobjgrppmu;
42 struct avfsfllobjs *pfll_objs = (struct avfsfllobjs *)
43 pboardobjgrp;
44 u32 status = 0;
45
46 gk20a_dbg_info("");
47
48 status = boardobjgrp_pmudatainit_e32(g, pboardobjgrp, pboardobjgrppmu);
49 if (status) {
50 gk20a_err(dev_from_gk20a(g), "failed to init fll pmuobjgrp");
51 return status;
52 }
53 pset->lut_num_entries = pfll_objs->lut_num_entries;
54 pset->lut_step_size_uv = pfll_objs->lut_step_size_uv;
55 pset->lut_min_voltage_uv = pfll_objs->lut_min_voltage_uv;
56 pset->max_min_freq_mhz = pfll_objs->max_min_freq_mhz;
57
58 status = boardobjgrpmask_export(
59 &pfll_objs->lut_prog_master_mask.super,
60 pfll_objs->lut_prog_master_mask.super.bitcount,
61 &pset->lut_prog_master_mask.super);
62
63 gk20a_dbg_info(" Done");
64 return status;
65}
66
67static u32 _clk_fll_devgrp_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_fll_device_boardobj_grp_set *pgrp_set =
73 (struct nv_pmu_clk_clk_fll_device_boardobj_grp_set *)
74 pmuboardobjgrp;
75
76 gk20a_dbg_info("");
77
78 /*check whether pmuboardobjgrp has a valid boardobj in index*/
79 if (((u32)BIT(idx) &
80 pgrp_set->hdr.data.super.obj_mask.super.data[0]) == 0)
81 return -EINVAL;
82
83 *ppboardobjpmudata = (struct nv_pmu_boardobj *)
84 &pgrp_set->objects[idx].data.board_obj;
85 gk20a_dbg_info(" Done");
86 return 0;
87}
88
89static u32 _clk_fll_devgrp_pmustatus_instget(struct gk20a *g,
90 void *pboardobjgrppmu,
91 struct nv_pmu_boardobj_query **ppboardobjpmustatus,
92 u8 idx)
93{
94 struct nv_pmu_clk_clk_fll_device_boardobj_grp_get_status *pgrp_get_status =
95 (struct nv_pmu_clk_clk_fll_device_boardobj_grp_get_status *)
96 pboardobjgrppmu;
97
98 /*check whether pmuboardobjgrp has a valid boardobj in index*/
99 if (((u32)BIT(idx) &
100 pgrp_get_status->hdr.data.super.obj_mask.super.data[0]) == 0)
101 return -EINVAL;
102
103 *ppboardobjpmustatus = (struct nv_pmu_boardobj_query *)
104 &pgrp_get_status->objects[idx].data.board_obj;
105 return 0;
106}
107
108u32 clk_fll_sw_setup(struct gk20a *g)
109{
110 u32 status;
111 struct boardobjgrp *pboardobjgrp = NULL;
112 struct avfsfllobjs *pfllobjs;
113 struct fll_device *pfll;
114 struct fll_device *pfll_master;
115 struct fll_device *pfll_local;
116 u8 i;
117 u8 j;
118
119 gk20a_dbg_info("");
120
121 status = boardobjgrpconstruct_e32(&g->clk_pmu.avfs_fllobjs.super);
122 if (status) {
123 gk20a_err(dev_from_gk20a(g),
124 "error creating boardobjgrp for fll, status - 0x%x", status);
125 goto done;
126 }
127 pfllobjs = &(g->clk_pmu.avfs_fllobjs);
128 pboardobjgrp = &(g->clk_pmu.avfs_fllobjs.super.super);
129
130 BOARDOBJGRP_PMU_CONSTRUCT(pboardobjgrp, CLK, FLL_DEVICE);
131
132 status = BOARDOBJGRP_PMU_CMD_GRP_SET_CONSTRUCT(g, pboardobjgrp,
133 clk, CLK, clk_fll_device, CLK_FLL_DEVICE);
134 if (status) {
135 gk20a_err(dev_from_gk20a(g),
136 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
137 status);
138 goto done;
139 }
140
141 pboardobjgrp->pmudatainit = _clk_fll_devgrp_pmudatainit_super;
142 pboardobjgrp->pmudatainstget = _clk_fll_devgrp_pmudata_instget;
143 pboardobjgrp->pmustatusinstget = _clk_fll_devgrp_pmustatus_instget;
144 pfllobjs = (struct avfsfllobjs *)pboardobjgrp;
145 pfllobjs->lut_num_entries = CTRL_CLK_LUT_NUM_ENTRIES;
146 pfllobjs->lut_step_size_uv = CTRL_CLK_VIN_STEP_SIZE_UV;
147 pfllobjs->lut_min_voltage_uv = CTRL_CLK_LUT_MIN_VOLTAGE_UV;
148
149 /* Initialize lut prog master mask to zero.*/
150 boardobjgrpmask_e32_init(&pfllobjs->lut_prog_master_mask, NULL);
151
152 status = devinit_get_fll_device_table(g, pfllobjs);
153 if (status)
154 goto done;
155
156 status = BOARDOBJGRP_PMU_CMD_GRP_GET_STATUS_CONSTRUCT(g,
157 &g->clk_pmu.avfs_fllobjs.super.super,
158 clk, CLK, clk_fll_device, CLK_FLL_DEVICE);
159 if (status) {
160 gk20a_err(dev_from_gk20a(g),
161 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
162 status);
163 goto done;
164 }
165
166 BOARDOBJGRP_FOR_EACH(&(pfllobjs->super.super),
167 struct fll_device *, pfll, i) {
168 pfll_master = NULL;
169 j = 0;
170 BOARDOBJGRP_ITERATOR(&(pfllobjs->super.super),
171 struct fll_device *, pfll_local, j,
172 &pfllobjs->lut_prog_master_mask.super) {
173 if (pfll_local->clk_domain == pfll->clk_domain) {
174 pfll_master = pfll_local;
175 break;
176 }
177 }
178
179 if (pfll_master == NULL) {
180 status = boardobjgrpmask_bitset(
181 &pfllobjs->lut_prog_master_mask.super,
182 BOARDOBJ_GET_IDX(pfll));
183 if (status) {
184 gk20a_err(dev_from_gk20a(g), "err setting lutprogmask");
185 goto done;
186 }
187 pfll_master = pfll;
188 }
189 status = pfll_master->lut_broadcast_slave_register(
190 g, pfllobjs, pfll_master, pfll);
191
192 if (status) {
193 gk20a_err(dev_from_gk20a(g), "err setting lutslavemask");
194 goto done;
195 }
196 }
197done:
198 gk20a_dbg_info(" done status %x", status);
199 return status;
200}
201
202u32 clk_fll_pmu_setup(struct gk20a *g)
203{
204 u32 status;
205 struct boardobjgrp *pboardobjgrp = NULL;
206
207 gk20a_dbg_info("");
208
209 pboardobjgrp = &g->clk_pmu.avfs_fllobjs.super.super;
210
211 if (!pboardobjgrp->bconstructed)
212 return -EINVAL;
213
214 status = pboardobjgrp->pmuinithandle(g, pboardobjgrp);
215
216 gk20a_dbg_info("Done");
217 return status;
218}
219
220static u32 devinit_get_fll_device_table(struct gk20a *g,
221 struct avfsfllobjs *pfllobjs)
222{
223 u32 status = 0;
224 u8 *fll_table_ptr = NULL;
225 struct fll_descriptor_header fll_desc_table_header_sz = { 0 };
226 struct fll_descriptor_header_10 fll_desc_table_header = { 0 };
227 struct fll_descriptor_entry_10 fll_desc_table_entry = { 0 };
228 u8 *fll_tbl_entry_ptr = NULL;
229 u32 index = 0;
230 struct fll_device fll_dev_data;
231 struct fll_device *pfll_dev;
232 struct vin_device *pvin_dev;
233 u32 desctablesize;
234 u32 vbios_domain = NV_PERF_DOMAIN_4X_CLOCK_DOMAIN_SKIP;
235 struct avfsvinobjs *pvinobjs = &g->clk_pmu.avfs_vinobjs;
236
237 gk20a_dbg_info("");
238
239 if (g->ops.bios.get_perf_table_ptrs) {
240 fll_table_ptr = (u8 *)g->ops.bios.get_perf_table_ptrs(g,
241 g->bios.clock_token, FLL_TABLE);
242 if (fll_table_ptr == NULL) {
243 status = -1;
244 goto done;
245 }
246 }
247
248 memcpy(&fll_desc_table_header_sz, fll_table_ptr,
249 sizeof(struct fll_descriptor_header));
250 if (fll_desc_table_header_sz.size >= FLL_DESCRIPTOR_HEADER_10_SIZE_6)
251 desctablesize = FLL_DESCRIPTOR_HEADER_10_SIZE_6;
252 else
253 desctablesize = FLL_DESCRIPTOR_HEADER_10_SIZE_4;
254
255 memcpy(&fll_desc_table_header, fll_table_ptr, desctablesize);
256
257 if (desctablesize == FLL_DESCRIPTOR_HEADER_10_SIZE_6)
258 pfllobjs->max_min_freq_mhz =
259 fll_desc_table_header.max_min_freq_mhz;
260 else
261 pfllobjs->max_min_freq_mhz = 0;
262
263 /* Read table entries*/
264 fll_tbl_entry_ptr = fll_table_ptr + desctablesize;
265 for (index = 0; index < fll_desc_table_header.entry_count; index++) {
266 u32 fll_id;
267
268 memcpy(&fll_desc_table_entry, fll_tbl_entry_ptr,
269 sizeof(struct fll_descriptor_entry_10));
270
271 if (fll_desc_table_entry.fll_device_type == CTRL_CLK_FLL_TYPE_DISABLED)
272 continue;
273
274 fll_id = fll_desc_table_entry.fll_device_id;
275
276 pvin_dev = CLK_GET_VIN_DEVICE(pvinobjs,
277 (u8)fll_desc_table_entry.vin_idx_logic);
278 if (pvin_dev == NULL)
279 return -EINVAL;
280
281 pvin_dev->flls_shared_mask |= BIT(fll_id);
282
283 pvin_dev = CLK_GET_VIN_DEVICE(pvinobjs,
284 (u8)fll_desc_table_entry.vin_idx_sram);
285 if (pvin_dev == NULL)
286 return -EINVAL;
287
288 pvin_dev->flls_shared_mask |= BIT(fll_id);
289
290 fll_dev_data.super.type =
291 (u8)fll_desc_table_entry.fll_device_type;
292 fll_dev_data.id = (u8)fll_desc_table_entry.fll_device_id;
293 fll_dev_data.mdiv = (u8)BIOS_GET_FIELD(
294 fll_desc_table_entry.fll_params,
295 NV_FLL_DESC_FLL_PARAMS_MDIV);
296 fll_dev_data.input_freq_mhz =
297 (u16)fll_desc_table_entry.ref_freq_mhz;
298 fll_dev_data.min_freq_vfe_idx =
299 (u8)fll_desc_table_entry.min_freq_vfe_idx;
300 fll_dev_data.freq_ctrl_idx = CTRL_BOARDOBJ_IDX_INVALID;
301
302 vbios_domain = (u32)(fll_desc_table_entry.clk_domain &
303 NV_PERF_DOMAIN_4X_CLOCK_DOMAIN_MASK);
304 if (vbios_domain == 0)
305 fll_dev_data.clk_domain = CTRL_CLK_DOMAIN_GPC2CLK;
306 else if (vbios_domain == 1)
307 fll_dev_data.clk_domain = CTRL_CLK_DOMAIN_XBAR2CLK;
308 else if (vbios_domain == 3)
309 fll_dev_data.clk_domain = CTRL_CLK_DOMAIN_SYS2CLK;
310 else
311 continue;
312
313 fll_dev_data.rail_idx_for_lut = 0;
314
315 fll_dev_data.vin_idx_logic =
316 (u8)fll_desc_table_entry.vin_idx_logic;
317 fll_dev_data.vin_idx_sram =
318 (u8)fll_desc_table_entry.vin_idx_sram;
319 fll_dev_data.lut_device.vselect_mode =
320 (u8)BIOS_GET_FIELD(fll_desc_table_entry.lut_params,
321 NV_FLL_DESC_LUT_PARAMS_VSELECT);
322 fll_dev_data.lut_device.hysteresis_threshold =
323 (u8)BIOS_GET_FIELD(fll_desc_table_entry.lut_params,
324 NV_FLL_DESC_LUT_PARAMS_HYSTERISIS_THRESHOLD);
325 fll_dev_data.regime_desc.regime_id =
326 CTRL_CLK_FLL_REGIME_ID_FFR;
327 fll_dev_data.regime_desc.fixed_freq_regime_limit_mhz =
328 (u16)fll_desc_table_entry.ffr_cutoff_freq_mhz;
329
330 /*construct fll device*/
331 pfll_dev = construct_fll_device(g, (void *)&fll_dev_data);
332
333 status = boardobjgrp_objinsert(&pfllobjs->super.super,
334 (struct boardobj *)pfll_dev, index);
335
336 fll_tbl_entry_ptr += fll_desc_table_header.entry_size;
337 }
338
339done:
340 gk20a_dbg_info(" done status %x", status);
341 return status;
342}
343
344static u32 lutbroadcastslaveregister(struct gk20a *g,
345 struct avfsfllobjs *pfllobjs,
346 struct fll_device *pfll,
347 struct fll_device *pfll_slave)
348{
349 if (pfll->clk_domain != pfll_slave->clk_domain)
350 return -EINVAL;
351
352 return boardobjgrpmask_bitset(&pfll->
353 lut_prog_broadcast_slave_mask.super,
354 BOARDOBJ_GET_IDX(pfll_slave));
355}
356
357static struct fll_device *construct_fll_device(struct gk20a *g,
358 void *pargs)
359{
360 struct boardobj *board_obj_ptr = NULL;
361 struct fll_device *pfll_dev;
362 struct fll_device *board_obj_fll_ptr = NULL;
363 u32 status;
364
365 gk20a_dbg_info("");
366 status = boardobj_construct_super(g, &board_obj_ptr,
367 sizeof(struct fll_device), pargs);
368 if (status)
369 return NULL;
370
371 pfll_dev = (struct fll_device *)pargs;
372 board_obj_fll_ptr = (struct fll_device *)board_obj_ptr;
373 board_obj_ptr->pmudatainit = fll_device_init_pmudata_super;
374 board_obj_fll_ptr->lut_broadcast_slave_register =
375 lutbroadcastslaveregister;
376 board_obj_fll_ptr->id = pfll_dev->id;
377 board_obj_fll_ptr->mdiv = pfll_dev->mdiv;
378 board_obj_fll_ptr->rail_idx_for_lut = pfll_dev->rail_idx_for_lut;
379 board_obj_fll_ptr->input_freq_mhz = pfll_dev->input_freq_mhz;
380 board_obj_fll_ptr->clk_domain = pfll_dev->clk_domain;
381 board_obj_fll_ptr->vin_idx_logic = pfll_dev->vin_idx_logic;
382 board_obj_fll_ptr->vin_idx_sram = pfll_dev->vin_idx_sram;
383 board_obj_fll_ptr->min_freq_vfe_idx =
384 pfll_dev->min_freq_vfe_idx;
385 board_obj_fll_ptr->freq_ctrl_idx = pfll_dev->freq_ctrl_idx;
386 memcpy(&board_obj_fll_ptr->lut_device, &pfll_dev->lut_device,
387 sizeof(struct nv_pmu_clk_lut_device_desc));
388 memcpy(&board_obj_fll_ptr->regime_desc, &pfll_dev->regime_desc,
389 sizeof(struct nv_pmu_clk_regime_desc));
390 boardobjgrpmask_e32_init(
391 &board_obj_fll_ptr->lut_prog_broadcast_slave_mask, NULL);
392
393 gk20a_dbg_info(" Done");
394
395 return (struct fll_device *)board_obj_ptr;
396}
397
398static u32 fll_device_init_pmudata_super(struct gk20a *g,
399 struct boardobj *board_obj_ptr,
400 struct nv_pmu_boardobj *ppmudata)
401{
402 u32 status = 0;
403 struct fll_device *pfll_dev;
404 struct nv_pmu_clk_clk_fll_device_boardobj_set *perf_pmu_data;
405
406 gk20a_dbg_info("");
407
408 status = boardobj_pmudatainit_super(g, board_obj_ptr, ppmudata);
409 if (status != 0)
410 return status;
411
412 pfll_dev = (struct fll_device *)board_obj_ptr;
413 perf_pmu_data = (struct nv_pmu_clk_clk_fll_device_boardobj_set *)
414 ppmudata;
415
416 perf_pmu_data->id = pfll_dev->id;
417 perf_pmu_data->mdiv = pfll_dev->mdiv;
418 perf_pmu_data->rail_idx_for_lut = pfll_dev->rail_idx_for_lut;
419 perf_pmu_data->input_freq_mhz = pfll_dev->input_freq_mhz;
420 perf_pmu_data->vin_idx_logic = pfll_dev->vin_idx_logic;
421 perf_pmu_data->vin_idx_sram = pfll_dev->vin_idx_sram;
422 perf_pmu_data->clk_domain = pfll_dev->clk_domain;
423 perf_pmu_data->min_freq_vfe_idx =
424 pfll_dev->min_freq_vfe_idx;
425 perf_pmu_data->freq_ctrl_idx = pfll_dev->freq_ctrl_idx;
426
427 memcpy(&perf_pmu_data->lut_device, &pfll_dev->lut_device,
428 sizeof(struct nv_pmu_clk_lut_device_desc));
429 memcpy(&perf_pmu_data->regime_desc, &pfll_dev->regime_desc,
430 sizeof(struct nv_pmu_clk_regime_desc));
431
432 status = boardobjgrpmask_export(
433 &pfll_dev->lut_prog_broadcast_slave_mask.super,
434 pfll_dev->lut_prog_broadcast_slave_mask.super.bitcount,
435 &perf_pmu_data->lut_prog_broadcast_slave_mask.super);
436
437 gk20a_dbg_info(" Done");
438
439 return status;
440}
diff --git a/drivers/gpu/nvgpu/clk/clk_fll.h b/drivers/gpu/nvgpu/clk/clk_fll.h
new file mode 100644
index 00000000..06872f48
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk_fll.h
@@ -0,0 +1,68 @@
1/*
2* Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
3*
4* This program is free software; you can redistribute it and/or modify it
5* under the terms and conditions of the GNU General Public License,
6* version 2, as published by the Free Software Foundation.
7*
8* This program is distributed in the hope it will be useful, but WITHOUT
9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11* more details.
12*/
13
14#ifndef _CLKFLL_H_
15#define _CLKFLL_H_
16
17#include "pmuif/gpmuifclk.h"
18#include "boardobj/boardobjgrp_e32.h"
19#include "boardobj/boardobjgrpmask.h"
20
21/*data and function definition to talk to driver*/
22u32 clk_fll_sw_setup(struct gk20a *g);
23u32 clk_fll_pmu_setup(struct gk20a *g);
24
25struct avfsfllobjs {
26 struct boardobjgrp_e32 super;
27 struct boardobjgrpmask_e32 lut_prog_master_mask;
28 u32 lut_step_size_uv;
29 u32 lut_min_voltage_uv;
30 u8 lut_num_entries;
31 u16 max_min_freq_mhz;
32};
33
34struct fll_device;
35
36typedef u32 fll_lut_broadcast_slave_register(struct gk20a *g,
37 struct avfsfllobjs *pfllobjs,
38 struct fll_device *pfll,
39 struct fll_device *pfll_slave);
40
41struct fll_device {
42 struct boardobj super;
43 u8 id;
44 u8 mdiv;
45 u16 input_freq_mhz;
46 u32 clk_domain;
47 u8 vin_idx_logic;
48 u8 vin_idx_sram;
49 u8 rail_idx_for_lut;
50 struct nv_pmu_clk_lut_device_desc lut_device;
51 struct nv_pmu_clk_regime_desc regime_desc;
52 u8 min_freq_vfe_idx;
53 u8 freq_ctrl_idx;
54 u8 target_regime_id_override;
55 struct boardobjgrpmask_e32 lut_prog_broadcast_slave_mask;
56 fll_lut_broadcast_slave_register *lut_broadcast_slave_register;
57};
58
59#define CLK_FLL_LUT_VF_NUM_ENTRIES(pclk) \
60 (pclk->avfs_fllobjs.lut_num_entries)
61
62#define CLK_FLL_LUT_MIN_VOLTAGE_UV(pclk) \
63 (pclk->avfs_fllobjs.lut_min_voltage_uv)
64#define CLK_FLL_LUT_STEP_SIZE_UV(pclk) \
65 (pclk->avfs_fllobjs.lut_step_size_uv)
66
67#endif
68
diff --git a/drivers/gpu/nvgpu/clk/clk_freq_controller.c b/drivers/gpu/nvgpu/clk/clk_freq_controller.c
new file mode 100644
index 00000000..17f79168
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk_freq_controller.c
@@ -0,0 +1,454 @@
1/*
2 * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 */
13
14#include "gk20a/gk20a.h"
15#include "clk.h"
16#include "clk_fll.h"
17#include "clk_domain.h"
18#include "clk_freq_controller.h"
19#include "include/bios.h"
20#include "boardobj/boardobjgrp.h"
21#include "boardobj/boardobjgrp_e32.h"
22#include "pmuif/gpmuifboardobj.h"
23#include "pmuif/gpmuifclk.h"
24#include "gm206/bios_gm206.h"
25#include "ctrl/ctrlclk.h"
26#include "ctrl/ctrlvolt.h"
27#include "gk20a/pmu_gk20a.h"
28
29static u32 clk_freq_controller_pmudatainit_super(struct gk20a *g,
30 struct boardobj *board_obj_ptr,
31 struct nv_pmu_boardobj *ppmudata)
32{
33 struct nv_pmu_clk_clk_freq_controller_boardobj_set *pfreq_cntlr_set;
34 struct clk_freq_controller *pfreq_cntlr;
35 u32 status = 0;
36
37 status = boardobj_pmudatainit_super(g, board_obj_ptr, ppmudata);
38 if (status)
39 return status;
40
41 pfreq_cntlr_set =
42 (struct nv_pmu_clk_clk_freq_controller_boardobj_set *)ppmudata;
43 pfreq_cntlr = (struct clk_freq_controller *)board_obj_ptr;
44
45 pfreq_cntlr_set->controller_id = pfreq_cntlr->controller_id;
46 pfreq_cntlr_set->clk_domain = pfreq_cntlr->clk_domain;
47 pfreq_cntlr_set->parts_freq_mode = pfreq_cntlr->parts_freq_mode;
48 pfreq_cntlr_set->bdisable = pfreq_cntlr->bdisable;
49 pfreq_cntlr_set->freq_cap_noise_unaware_vmin_above =
50 pfreq_cntlr->freq_cap_noise_unaware_vmin_above;
51 pfreq_cntlr_set->freq_cap_noise_unaware_vmin_below =
52 pfreq_cntlr->freq_cap_noise_unaware_vmin_below;
53 pfreq_cntlr_set->freq_hyst_pos_mhz = pfreq_cntlr->freq_hyst_pos_mhz;
54 pfreq_cntlr_set->freq_hyst_neg_mhz = pfreq_cntlr->freq_hyst_neg_mhz;
55
56 return status;
57}
58
59static u32 clk_freq_controller_pmudatainit_pi(struct gk20a *g,
60 struct boardobj *board_obj_ptr,
61 struct nv_pmu_boardobj *ppmudata)
62{
63 struct nv_pmu_clk_clk_freq_controller_pi_boardobj_set
64 *pfreq_cntlr_pi_set;
65 struct clk_freq_controller_pi *pfreq_cntlr_pi;
66 u32 status = 0;
67
68 status = clk_freq_controller_pmudatainit_super(g,
69 board_obj_ptr, ppmudata);
70 if (status)
71 return -1;
72
73 pfreq_cntlr_pi_set =
74 (struct nv_pmu_clk_clk_freq_controller_pi_boardobj_set *)
75 ppmudata;
76 pfreq_cntlr_pi = (struct clk_freq_controller_pi *)board_obj_ptr;
77
78 pfreq_cntlr_pi_set->prop_gain = pfreq_cntlr_pi->prop_gain;
79 pfreq_cntlr_pi_set->integ_gain = pfreq_cntlr_pi->integ_gain;
80 pfreq_cntlr_pi_set->integ_decay = pfreq_cntlr_pi->integ_decay;
81 pfreq_cntlr_pi_set->volt_delta_min = pfreq_cntlr_pi->volt_delta_min;
82 pfreq_cntlr_pi_set->volt_delta_max = pfreq_cntlr_pi->volt_delta_max;
83 pfreq_cntlr_pi_set->slowdown_pct_min = pfreq_cntlr_pi->slowdown_pct_min;
84 pfreq_cntlr_pi_set->bpoison = pfreq_cntlr_pi->bpoison;
85
86 return status;
87}
88
89static u32 clk_freq_controller_construct_super(struct gk20a *g,
90 struct boardobj **ppboardobj,
91 u16 size, void *pargs)
92{
93 struct clk_freq_controller *pfreq_cntlr = NULL;
94 struct clk_freq_controller *pfreq_cntlr_tmp = NULL;
95 u32 status = 0;
96
97 status = boardobj_construct_super(g, ppboardobj, size, pargs);
98 if (status)
99 return -EINVAL;
100
101 pfreq_cntlr_tmp = (struct clk_freq_controller *)pargs;
102 pfreq_cntlr = (struct clk_freq_controller *)*ppboardobj;
103
104 pfreq_cntlr->super.pmudatainit = clk_freq_controller_pmudatainit_super;
105
106 pfreq_cntlr->controller_id = pfreq_cntlr_tmp->controller_id;
107 pfreq_cntlr->clk_domain = pfreq_cntlr_tmp->clk_domain;
108 pfreq_cntlr->parts_freq_mode = pfreq_cntlr_tmp->parts_freq_mode;
109 pfreq_cntlr->freq_cap_noise_unaware_vmin_above =
110 pfreq_cntlr_tmp->freq_cap_noise_unaware_vmin_above;
111 pfreq_cntlr->freq_cap_noise_unaware_vmin_below =
112 pfreq_cntlr_tmp->freq_cap_noise_unaware_vmin_below;
113 pfreq_cntlr->freq_hyst_pos_mhz = pfreq_cntlr_tmp->freq_hyst_pos_mhz;
114 pfreq_cntlr->freq_hyst_neg_mhz = pfreq_cntlr_tmp->freq_hyst_neg_mhz;
115
116 return status;
117}
118
119static u32 clk_freq_controller_construct_pi(struct gk20a *g,
120 struct boardobj **ppboardobj,
121 u16 size, void *pargs)
122{
123 struct clk_freq_controller_pi *pfreq_cntlr_pi = NULL;
124 struct clk_freq_controller_pi *pfreq_cntlr_pi_tmp = NULL;
125 u32 status = 0;
126
127 status = clk_freq_controller_construct_super(g, ppboardobj,
128 size, pargs);
129 if (status)
130 return -EINVAL;
131
132 pfreq_cntlr_pi = (struct clk_freq_controller_pi *)*ppboardobj;
133 pfreq_cntlr_pi_tmp = (struct clk_freq_controller_pi *)pargs;
134
135 pfreq_cntlr_pi->super.super.pmudatainit =
136 clk_freq_controller_pmudatainit_pi;
137
138 pfreq_cntlr_pi->prop_gain = pfreq_cntlr_pi_tmp->prop_gain;
139 pfreq_cntlr_pi->integ_gain = pfreq_cntlr_pi_tmp->integ_gain;
140 pfreq_cntlr_pi->integ_decay = pfreq_cntlr_pi_tmp->integ_decay;
141 pfreq_cntlr_pi->volt_delta_min = pfreq_cntlr_pi_tmp->volt_delta_min;
142 pfreq_cntlr_pi->volt_delta_max = pfreq_cntlr_pi_tmp->volt_delta_max;
143 pfreq_cntlr_pi->slowdown_pct_min = pfreq_cntlr_pi_tmp->slowdown_pct_min;
144 pfreq_cntlr_pi->bpoison = pfreq_cntlr_pi_tmp->bpoison;
145
146 return status;
147}
148
149struct clk_freq_controller *clk_clk_freq_controller_construct(struct gk20a *g,
150 void *pargs)
151{
152 struct boardobj *board_obj_ptr = NULL;
153 u32 status = 0;
154
155 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_CLK_CLK_FREQ_CONTROLLER_TYPE_PI)
156 return NULL;
157
158 status = clk_freq_controller_construct_pi(g, &board_obj_ptr,
159 sizeof(struct clk_freq_controller_pi), pargs);
160 if (status)
161 return NULL;
162
163 return (struct clk_freq_controller *)board_obj_ptr;
164}
165
166
167static u32 clk_get_freq_controller_table(struct gk20a *g,
168 struct clk_freq_controllers *pclk_freq_controllers)
169{
170 u32 status = 0;
171 u8 *pfreq_controller_table_ptr = NULL;
172 struct vbios_fct_1x_header header = { 0 };
173 struct vbios_fct_1x_entry entry = { 0 };
174 u8 entry_idx;
175 u8 *entry_offset;
176 u32 freq_controller_id;
177 struct clk_freq_controller *pclk_freq_cntr = NULL;
178 struct clk_freq_controller *ptmp_freq_cntr = NULL;
179 struct clk_freq_controller_pi *ptmp_freq_cntr_pi = NULL;
180 struct clk_domain *pclk_domain;
181
182 struct freq_controller_data_type {
183 union {
184 struct boardobj board_obj;
185 struct clk_freq_controller freq_controller;
186 struct clk_freq_controller_pi freq_controller_pi;
187 };
188 } freq_controller_data;
189
190 if (g->ops.bios.get_perf_table_ptrs) {
191 pfreq_controller_table_ptr =
192 (u8 *)g->ops.bios.get_perf_table_ptrs(g,
193 g->bios.clock_token,
194 FREQUENCY_CONTROLLER_TABLE);
195 if (pfreq_controller_table_ptr == NULL) {
196 status = -EINVAL;
197 goto done;
198 }
199 } else {
200 status = -EINVAL;
201 goto done;
202 }
203
204 memcpy(&header, pfreq_controller_table_ptr,
205 sizeof(struct vbios_fct_1x_header));
206
207 pclk_freq_controllers->sampling_period_ms = header.sampling_period_ms;
208 pclk_freq_controllers->volt_policy_idx = 0;
209
210 /* Read in the entries. */
211 for (entry_idx = 0; entry_idx < header.entry_count; entry_idx++) {
212 entry_offset = (pfreq_controller_table_ptr +
213 header.header_size + (entry_idx * header.entry_size));
214
215 memset(&freq_controller_data, 0x0,
216 sizeof(struct freq_controller_data_type));
217 ptmp_freq_cntr = &freq_controller_data.freq_controller;
218 ptmp_freq_cntr_pi = &freq_controller_data.freq_controller_pi;
219
220 memcpy(&entry, entry_offset,
221 sizeof(struct vbios_fct_1x_entry));
222
223 if (!BIOS_GET_FIELD(entry.flags0,
224 NV_VBIOS_FCT_1X_ENTRY_FLAGS0_TYPE))
225 continue;
226
227 freq_controller_data.board_obj.type = (u8)BIOS_GET_FIELD(
228 entry.flags0, NV_VBIOS_FCT_1X_ENTRY_FLAGS0_TYPE);
229
230 ptmp_freq_cntr->controller_id =
231 (u8)BIOS_GET_FIELD(entry.param0,
232 NV_VBIOS_FCT_1X_ENTRY_PARAM0_ID);
233
234 freq_controller_id = ptmp_freq_cntr->controller_id;
235
236 pclk_domain = CLK_CLK_DOMAIN_GET((&g->clk_pmu),
237 (u32)entry.clk_domain_idx);
238 freq_controller_data.freq_controller.clk_domain =
239 pclk_domain->api_domain;
240
241 ptmp_freq_cntr->parts_freq_mode =
242 (u8)BIOS_GET_FIELD(entry.param0,
243 NV_VBIOS_FCT_1X_ENTRY_PARAM0_FREQ_MODE);
244
245 /* Populate PI specific data */
246 ptmp_freq_cntr_pi->slowdown_pct_min =
247 (u8)BIOS_GET_FIELD(entry.param1,
248 NV_VBIOS_FCT_1X_ENTRY_PARAM1_SLOWDOWN_PCT_MIN);
249
250 ptmp_freq_cntr_pi->bpoison =
251 BIOS_GET_FIELD(entry.param1,
252 NV_VBIOS_FCT_1X_ENTRY_PARAM1_POISON);
253
254 ptmp_freq_cntr_pi->prop_gain =
255 (s32)BIOS_GET_FIELD(entry.param2,
256 NV_VBIOS_FCT_1X_ENTRY_PARAM2_PROP_GAIN);
257
258 ptmp_freq_cntr_pi->integ_gain =
259 (s32)BIOS_GET_FIELD(entry.param3,
260 NV_VBIOS_FCT_1X_ENTRY_PARAM3_INTEG_GAIN);
261
262 ptmp_freq_cntr_pi->integ_decay =
263 (s32)BIOS_GET_FIELD(entry.param4,
264 NV_VBIOS_FCT_1X_ENTRY_PARAM4_INTEG_DECAY);
265
266 ptmp_freq_cntr_pi->volt_delta_min =
267 (s32)BIOS_GET_FIELD(entry.param5,
268 NV_VBIOS_FCT_1X_ENTRY_PARAM5_VOLT_DELTA_MIN);
269
270 ptmp_freq_cntr_pi->volt_delta_max =
271 (s32)BIOS_GET_FIELD(entry.param6,
272 NV_VBIOS_FCT_1X_ENTRY_PARAM6_VOLT_DELTA_MAX);
273
274 ptmp_freq_cntr->freq_cap_noise_unaware_vmin_above =
275 (s16)BIOS_GET_FIELD(entry.param7,
276 NV_VBIOS_FCT_1X_ENTRY_PARAM7_FREQ_CAP_VF);
277
278 ptmp_freq_cntr->freq_cap_noise_unaware_vmin_below =
279 (s16)BIOS_GET_FIELD(entry.param7,
280 NV_VBIOS_FCT_1X_ENTRY_PARAM7_FREQ_CAP_VMIN);
281
282 ptmp_freq_cntr->freq_hyst_pos_mhz =
283 (s16)BIOS_GET_FIELD(entry.param8,
284 NV_VBIOS_FCT_1X_ENTRY_PARAM8_FREQ_HYST_POS);
285 ptmp_freq_cntr->freq_hyst_neg_mhz =
286 (s16)BIOS_GET_FIELD(entry.param8,
287 NV_VBIOS_FCT_1X_ENTRY_PARAM8_FREQ_HYST_NEG);
288
289 if (ptmp_freq_cntr_pi->volt_delta_max <
290 ptmp_freq_cntr_pi->volt_delta_min)
291 goto done;
292
293 pclk_freq_cntr = clk_clk_freq_controller_construct(g,
294 (void *)&freq_controller_data);
295
296 if (pclk_freq_cntr == NULL) {
297 gk20a_err(dev_from_gk20a(g),
298 "unable to construct clock freq cntlr boardobj for %d",
299 entry_idx);
300 status = -EINVAL;
301 goto done;
302 }
303
304 status = boardobjgrp_objinsert(
305 &pclk_freq_controllers->super.super,
306 (struct boardobj *)pclk_freq_cntr, entry_idx);
307 if (status) {
308 gk20a_err(dev_from_gk20a(g),
309 "unable to insert clock freq cntlr boardobj for");
310 status = -EINVAL;
311 goto done;
312 }
313
314 }
315
316done:
317 return status;
318}
319
320u32 clk_freq_controller_pmu_setup(struct gk20a *g)
321{
322 u32 status;
323 struct boardobjgrp *pboardobjgrp = NULL;
324
325 gk20a_dbg_info("");
326
327 pboardobjgrp = &g->clk_pmu.clk_freq_controllers.super.super;
328
329 if (!pboardobjgrp->bconstructed)
330 return -EINVAL;
331
332 status = pboardobjgrp->pmuinithandle(g, pboardobjgrp);
333
334 gk20a_dbg_info("Done");
335 return status;
336}
337
338static u32 _clk_freq_controller_devgrp_pmudata_instget(struct gk20a *g,
339 struct nv_pmu_boardobjgrp *pmuboardobjgrp,
340 struct nv_pmu_boardobj **ppboardobjpmudata,
341 u8 idx)
342{
343 struct nv_pmu_clk_clk_freq_controller_boardobj_grp_set *pgrp_set =
344 (struct nv_pmu_clk_clk_freq_controller_boardobj_grp_set *)
345 pmuboardobjgrp;
346
347 gk20a_dbg_info("");
348
349 /*check whether pmuboardobjgrp has a valid boardobj in index*/
350 if (((u32)BIT(idx) &
351 pgrp_set->hdr.data.super.obj_mask.super.data[0]) == 0)
352 return -EINVAL;
353
354 *ppboardobjpmudata = (struct nv_pmu_boardobj *)
355 &pgrp_set->objects[idx].data.board_obj;
356 gk20a_dbg_info(" Done");
357 return 0;
358}
359
360static u32 _clk_freq_controllers_pmudatainit(struct gk20a *g,
361 struct boardobjgrp *pboardobjgrp,
362 struct nv_pmu_boardobjgrp_super *pboardobjgrppmu)
363{
364 struct nv_pmu_clk_clk_freq_controller_boardobjgrp_set_header *pset =
365 (struct nv_pmu_clk_clk_freq_controller_boardobjgrp_set_header *)
366 pboardobjgrppmu;
367 struct clk_freq_controllers *pcntrs =
368 (struct clk_freq_controllers *)pboardobjgrp;
369 u32 status = 0;
370
371 status = boardobjgrp_pmudatainit_e32(g, pboardobjgrp, pboardobjgrppmu);
372 if (status) {
373 gk20a_err(dev_from_gk20a(g),
374 "error updating pmu boardobjgrp for clk freq ctrs 0x%x",
375 status);
376 goto done;
377 }
378 pset->sampling_period_ms = pcntrs->sampling_period_ms;
379 pset->volt_policy_idx = pcntrs->volt_policy_idx;
380
381done:
382 return status;
383}
384
385u32 clk_freq_controller_sw_setup(struct gk20a *g)
386{
387 u32 status = 0;
388 struct boardobjgrp *pboardobjgrp = NULL;
389 struct clk_freq_controllers *pclk_freq_controllers;
390 struct avfsfllobjs *pfllobjs = &(g->clk_pmu.avfs_fllobjs);
391 struct fll_device *pfll;
392 struct clk_freq_controller *pclkfreqctrl;
393 u8 i;
394 u8 j;
395
396 gk20a_dbg_info("");
397
398 pclk_freq_controllers = &g->clk_pmu.clk_freq_controllers;
399 status = boardobjgrpconstruct_e32(&pclk_freq_controllers->super);
400 if (status) {
401 gk20a_err(dev_from_gk20a(g),
402 "error creating boardobjgrp for clk FCT, status - 0x%x",
403 status);
404 goto done;
405 }
406
407 pboardobjgrp = &g->clk_pmu.clk_freq_controllers.super.super;
408
409 pboardobjgrp->pmudatainit = _clk_freq_controllers_pmudatainit;
410 pboardobjgrp->pmudatainstget =
411 _clk_freq_controller_devgrp_pmudata_instget;
412 pboardobjgrp->pmustatusinstget = NULL;
413
414 /* Initialize mask to zero.*/
415 boardobjgrpmask_e32_init(&pclk_freq_controllers->freq_ctrl_load_mask,
416 NULL);
417
418 BOARDOBJGRP_PMU_CONSTRUCT(pboardobjgrp, CLK, CLK_FREQ_CONTROLLER);
419
420 status = BOARDOBJGRP_PMU_CMD_GRP_SET_CONSTRUCT(g, pboardobjgrp,
421 clk, CLK, clk_freq_controller, CLK_FREQ_CONTROLLER);
422 if (status) {
423 gk20a_err(dev_from_gk20a(g),
424 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
425 status);
426 goto done;
427 }
428
429 status = clk_get_freq_controller_table(g, pclk_freq_controllers);
430 if (status) {
431 gk20a_err(dev_from_gk20a(g),
432 "error reading freq controller table - 0x%x",
433 status);
434 goto done;
435 }
436
437 BOARDOBJGRP_FOR_EACH(&(pclk_freq_controllers->super.super),
438 struct clk_freq_controller *, pclkfreqctrl, i) {
439 pfll = NULL;
440 j = 0;
441 BOARDOBJGRP_FOR_EACH(&(pfllobjs->super.super),
442 struct fll_device *, pfll, j) {
443 if (pclkfreqctrl->controller_id == pfll->id) {
444 pfll->freq_ctrl_idx = i;
445 break;
446 }
447 }
448 boardobjgrpmask_bitset(&pclk_freq_controllers->
449 freq_ctrl_load_mask.super, i);
450 }
451done:
452 gk20a_dbg_info(" done status %x", status);
453 return status;
454}
diff --git a/drivers/gpu/nvgpu/clk/clk_freq_controller.h b/drivers/gpu/nvgpu/clk/clk_freq_controller.h
new file mode 100644
index 00000000..957a4f08
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk_freq_controller.h
@@ -0,0 +1,74 @@
1/*
2* Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
3*
4* This program is free software; you can redistribute it and/or modify it
5* under the terms and conditions of the GNU General Public License,
6* version 2, as published by the Free Software Foundation.
7*
8* This program is distributed in the hope it will be useful, but WITHOUT
9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11* more details.
12*/
13
14#ifndef _CLK_FREQ_CONTROLLER_H_
15#define _CLK_FREQ_CONTROLLER_H_
16
17#define CTRL_CLK_CLK_FREQ_CONTROLLER_ID_SYS 0x00
18#define CTRL_CLK_CLK_FREQ_CONTROLLER_ID_LTC 0x01
19#define CTRL_CLK_CLK_FREQ_CONTROLLER_ID_XBAR 0x02
20#define CTRL_CLK_CLK_FREQ_CONTROLLER_ID_GPC0 0x03
21#define CTRL_CLK_CLK_FREQ_CONTROLLER_ID_GPC1 0x04
22#define CTRL_CLK_CLK_FREQ_CONTROLLER_ID_GPC2 0x05
23#define CTRL_CLK_CLK_FREQ_CONTROLLER_ID_GPC3 0x06
24#define CTRL_CLK_CLK_FREQ_CONTROLLER_ID_GPC4 0x07
25#define CTRL_CLK_CLK_FREQ_CONTROLLER_ID_GPC5 0x08
26#define CTRL_CLK_CLK_FREQ_CONTROLLER_ID_GPCS 0x09
27
28#define CTRL_CLK_CLK_FREQ_CONTROLLER_MASK_UNICAST_GPC \
29 (BIT(CTRL_CLK_CLK_FREQ_CONTROLLER_ID_GPC0) | \
30 BIT(CTRL_CLK_CLK_FREQ_CONTROLLER_ID_GPC1) | \
31 BIT(CTRL_CLK_CLK_FREQ_CONTROLLER_ID_GPC2) | \
32 BIT(CTRL_CLK_CLK_FREQ_CONTROLLER_ID_GPC3) | \
33 BIT(CTRL_CLK_CLK_FREQ_CONTROLLER_ID_GPC4) | \
34 BIT(CTRL_CLK_CLK_FREQ_CONTROLLER_ID_GPC5))
35
36#define CTRL_CLK_CLK_FREQ_CONTROLLER_TYPE_DISABLED 0x00
37#define CTRL_CLK_CLK_FREQ_CONTROLLER_TYPE_PI 0x01
38
39
40struct clk_freq_controller {
41 struct boardobj super;
42 u8 controller_id;
43 u8 parts_freq_mode;
44 bool bdisable;
45 u32 clk_domain;
46 s16 freq_cap_noise_unaware_vmin_above;
47 s16 freq_cap_noise_unaware_vmin_below;
48 s16 freq_hyst_pos_mhz;
49 s16 freq_hyst_neg_mhz;
50};
51
52struct clk_freq_controller_pi {
53 struct clk_freq_controller super;
54 s32 prop_gain;
55 s32 integ_gain;
56 s32 integ_decay;
57 s32 volt_delta_min;
58 s32 volt_delta_max;
59 u8 slowdown_pct_min;
60 bool bpoison;
61};
62
63struct clk_freq_controllers {
64 struct boardobjgrp_e32 super;
65 u32 sampling_period_ms;
66 struct boardobjgrpmask_e32 freq_ctrl_load_mask;
67 u8 volt_policy_idx;
68 void *pprereq_load;
69};
70
71u32 clk_freq_controller_sw_setup(struct gk20a *g);
72u32 clk_freq_controller_pmu_setup(struct gk20a *g);
73
74#endif
diff --git a/drivers/gpu/nvgpu/clk/clk_mclk.c b/drivers/gpu/nvgpu/clk/clk_mclk.c
new file mode 100644
index 00000000..06ff9082
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk_mclk.c
@@ -0,0 +1,2499 @@
1/*
2 * Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 */
13
14#include "gk20a/gk20a.h"
15#include <linux/delay.h>
16#include "pmuif/gpmuifseq.h"
17#include "gm206/bios_gm206.h"
18#include "gk20a/pmu_gk20a.h"
19#include "gk20a/hw_pwr_gk20a.h"
20#include "gp106/hw_fb_gp106.h"
21
22#include "include/bios.h"
23
24#define VREG_COUNT 24
25
26struct memory_link_training_pattern {
27 u32 regaddr;
28 u32 writeval;
29};
30
31static struct memory_link_training_pattern memory_pattern_reglist[] = {
32 {0x9a0968, 0x0},
33 {0x9a0920, 0x0},
34 {0x9a0918, 0x0},
35 {0x9a0920, 0x100},
36 {0x9a0918, 0x0},
37 {0x9a096c, 0x0},
38 {0x9a0924, 0x0},
39 {0x9a091c, 0x0},
40 {0x9a0924, 0x100},
41 {0x9a091c, 0x0},
42 {0x9a0968, 0x100},
43 {0x9a0920, 0xff},
44 {0x9a0918, 0xffffffff},
45 {0x9a0920, 0x1ff},
46 {0x9a0918, 0xffffffff},
47 {0x9a096c, 0x100},
48 {0x9a0924, 0xff},
49 {0x9a091c, 0xffffffff},
50 {0x9a0924, 0x1ff},
51 {0x9a091c, 0xffffffff},
52 {0x9a0968, 0x200},
53 {0x9a0920, 0xff},
54 {0x9a0918, 0x55555555},
55 {0x9a0920, 0x1ff},
56 {0x9a0918, 0x55555555},
57 {0x9a096c, 0x200},
58 {0x9a0924, 0xff},
59 {0x9a091c, 0x55555555},
60 {0x9a0924, 0x1ff},
61 {0x9a091c, 0x55555555},
62 {0x9a0968, 0x300},
63 {0x9a0920, 0x0},
64 {0x9a0918, 0xaaaaaaaa},
65 {0x9a0920, 0x100},
66 {0x9a0918, 0xaaaaaaaa},
67 {0x9a096c, 0x300},
68 {0x9a0924, 0x0},
69 {0x9a091c, 0xaaaaaaaa},
70 {0x9a0924, 0x100},
71 {0x9a091c, 0xaaaaaaaa},
72 {0x9a0968, 0x400},
73 {0x9a0920, 0xff},
74 {0x9a0918, 0x33333333},
75 {0x9a0920, 0x1ff},
76 {0x9a0918, 0x33333333},
77 {0x9a096c, 0x400},
78 {0x9a0924, 0xff},
79 {0x9a091c, 0x33333333},
80 {0x9a0924, 0x1ff},
81 {0x9a091c, 0x33333333},
82 {0x9a0968, 0x500},
83 {0x9a0920, 0x0},
84 {0x9a0918, 0xcccccccc},
85 {0x9a0920, 0x100},
86 {0x9a0918, 0xcccccccc},
87 {0x9a096c, 0x500},
88 {0x9a0924, 0x0},
89 {0x9a091c, 0xcccccccc},
90 {0x9a0924, 0x100},
91 {0x9a091c, 0xcccccccc},
92 {0x9a0968, 0x600},
93 {0x9a0920, 0x0},
94 {0x9a0918, 0xf0f0f0f0},
95 {0x9a0920, 0x100},
96 {0x9a0918, 0xf0f0f0f0},
97 {0x9a096c, 0x600},
98 {0x9a0924, 0x0},
99 {0x9a091c, 0xf0f0f0f0},
100 {0x9a0924, 0x100},
101 {0x9a091c, 0xf0f0f0f0},
102 {0x9a0968, 0x700},
103 {0x9a0920, 0xff},
104 {0x9a0918, 0xf0f0f0f},
105 {0x9a0920, 0x1ff},
106 {0x9a0918, 0xf0f0f0f},
107 {0x9a096c, 0x700},
108 {0x9a0924, 0xff},
109 {0x9a091c, 0xf0f0f0f},
110 {0x9a0924, 0x1ff},
111 {0x9a091c, 0xf0f0f0f},
112 {0x9a0968, 0x800},
113 {0x9a0920, 0xff},
114 {0x9a0918, 0xff00ff},
115 {0x9a0920, 0x1ff},
116 {0x9a0918, 0xff00ff},
117 {0x9a096c, 0x800},
118 {0x9a0924, 0xff},
119 {0x9a091c, 0xff00ff},
120 {0x9a0924, 0x1ff},
121 {0x9a091c, 0xff00ff},
122 {0x9a0968, 0x900},
123 {0x9a0920, 0x0},
124 {0x9a0918, 0xff00ff00},
125 {0x9a0920, 0x100},
126 {0x9a0918, 0xff00ff00},
127 {0x9a096c, 0x900},
128 {0x9a0924, 0x0},
129 {0x9a091c, 0xff00ff00},
130 {0x9a0924, 0x100},
131 {0x9a091c, 0xff00ff00},
132 {0x9a0968, 0xa00},
133 {0x9a0920, 0xff},
134 {0x9a0918, 0xffff},
135 {0x9a0920, 0x1ff},
136 {0x9a0918, 0xffff},
137 {0x9a096c, 0xa00},
138 {0x9a0924, 0xff},
139 {0x9a091c, 0xffff},
140 {0x9a0924, 0x1ff},
141 {0x9a091c, 0xffff},
142 {0x9a0968, 0xb00},
143 {0x9a0920, 0x0},
144 {0x9a0918, 0xffff0000},
145 {0x9a0920, 0x100},
146 {0x9a0918, 0xffff0000},
147 {0x9a096c, 0xb00},
148 {0x9a0924, 0x0},
149 {0x9a091c, 0xffff0000},
150 {0x9a0924, 0x100},
151 {0x9a091c, 0xffff0000},
152 {0x9a0968, 0xc00},
153 {0x9a0920, 0x0},
154 {0x9a0918, 0x0},
155 {0x9a0920, 0x100},
156 {0x9a0918, 0x0},
157 {0x9a096c, 0xc00},
158 {0x9a0924, 0x0},
159 {0x9a091c, 0x0},
160 {0x9a0924, 0x100},
161 {0x9a091c, 0x0},
162 {0x9a0968, 0xd00},
163 {0x9a0920, 0xff},
164 {0x9a0918, 0xffffffff},
165 {0x9a0920, 0x1ff},
166 {0x9a0918, 0xffffffff},
167 {0x9a096c, 0xd00},
168 {0x9a0924, 0xff},
169 {0x9a091c, 0xffffffff},
170 {0x9a0924, 0x1ff},
171 {0x9a091c, 0xffffffff},
172 {0x9a0968, 0xe00},
173 {0x9a0920, 0xff},
174 {0x9a0918, 0x55555555},
175 {0x9a0920, 0x1ff},
176 {0x9a0918, 0x55555555},
177 {0x9a096c, 0xe00},
178 {0x9a0924, 0xff},
179 {0x9a091c, 0x55555555},
180 {0x9a0924, 0x1ff},
181 {0x9a091c, 0x55555555},
182 {0x9a0968, 0xf00},
183 {0x9a0920, 0x0},
184 {0x9a0918, 0xaaaaaaaa},
185 {0x9a0920, 0x100},
186 {0x9a0918, 0xaaaaaaaa},
187 {0x9a096c, 0xf00},
188 {0x9a0924, 0x0},
189 {0x9a091c, 0xaaaaaaaa},
190 {0x9a0924, 0x100},
191 {0x9a091c, 0xaaaaaaaa},
192 {0x9a0968, 0x1000},
193 {0x9a0920, 0xff},
194 {0x9a0918, 0x33333333},
195 {0x9a0920, 0x1ff},
196 {0x9a0918, 0x33333333},
197 {0x9a096c, 0x1000},
198 {0x9a0924, 0xff},
199 {0x9a091c, 0x33333333},
200 {0x9a0924, 0x1ff},
201 {0x9a091c, 0x33333333},
202 {0x9a0968, 0x1100},
203 {0x9a0920, 0x0},
204 {0x9a0918, 0xcccccccc},
205 {0x9a0920, 0x100},
206 {0x9a0918, 0xcccccccc},
207 {0x9a096c, 0x1100},
208 {0x9a0924, 0x0},
209 {0x9a091c, 0xcccccccc},
210 {0x9a0924, 0x100},
211 {0x9a091c, 0xcccccccc},
212 {0x9a0968, 0x1200},
213 {0x9a0920, 0x0},
214 {0x9a0918, 0xf0f0f0f0},
215 {0x9a0920, 0x100},
216 {0x9a0918, 0xf0f0f0f0},
217 {0x9a096c, 0x1200},
218 {0x9a0924, 0x0},
219 {0x9a091c, 0xf0f0f0f0},
220 {0x9a0924, 0x100},
221 {0x9a091c, 0xf0f0f0f0},
222 {0x9a0968, 0x1300},
223 {0x9a0920, 0xff},
224 {0x9a0918, 0xf0f0f0f},
225 {0x9a0920, 0x1ff},
226 {0x9a0918, 0xf0f0f0f},
227 {0x9a096c, 0x1300},
228 {0x9a0924, 0xff},
229 {0x9a091c, 0xf0f0f0f},
230 {0x9a0924, 0x1ff},
231 {0x9a091c, 0xf0f0f0f},
232 {0x9a0968, 0x1400},
233 {0x9a0920, 0xff},
234 {0x9a0918, 0xff00ff},
235 {0x9a0920, 0x1ff},
236 {0x9a0918, 0xff00ff},
237 {0x9a096c, 0x1400},
238 {0x9a0924, 0xff},
239 {0x9a091c, 0xff00ff},
240 {0x9a0924, 0x1ff},
241 {0x9a091c, 0xff00ff},
242 {0x9a0968, 0x1500},
243 {0x9a0920, 0x0},
244 {0x9a0918, 0xff00ff00},
245 {0x9a0920, 0x100},
246 {0x9a0918, 0xff00ff00},
247 {0x9a096c, 0x1500},
248 {0x9a0924, 0x0},
249 {0x9a091c, 0xff00ff00},
250 {0x9a0924, 0x100},
251 {0x9a091c, 0xff00ff00},
252 {0x9a0968, 0x1600},
253 {0x9a0920, 0xff},
254 {0x9a0918, 0xffff},
255 {0x9a0920, 0x1ff},
256 {0x9a0918, 0xffff},
257 {0x9a096c, 0x1600},
258 {0x9a0924, 0xff},
259 {0x9a091c, 0xffff},
260 {0x9a0924, 0x1ff},
261 {0x9a091c, 0xffff},
262 {0x9a0968, 0x1700},
263 {0x9a0920, 0x0},
264 {0x9a0918, 0xffff0000},
265 {0x9a0920, 0x100},
266 {0x9a0918, 0xffff0000},
267 {0x9a096c, 0x1700},
268 {0x9a0924, 0x0},
269 {0x9a091c, 0xffff0000},
270 {0x9a0924, 0x100},
271 {0x9a091c, 0xffff0000},
272 {0x9a0968, 0x1800},
273 {0x9a0920, 0x0},
274 {0x9a0918, 0x0},
275 {0x9a0920, 0x100},
276 {0x9a0918, 0x0},
277 {0x9a096c, 0x1800},
278 {0x9a0924, 0x0},
279 {0x9a091c, 0x0},
280 {0x9a0924, 0x100},
281 {0x9a091c, 0x0},
282 {0x9a0968, 0x1900},
283 {0x9a0920, 0xff},
284 {0x9a0918, 0xffffffff},
285 {0x9a0920, 0x1ff},
286 {0x9a0918, 0xffffffff},
287 {0x9a096c, 0x1900},
288 {0x9a0924, 0xff},
289 {0x9a091c, 0xffffffff},
290 {0x9a0924, 0x1ff},
291 {0x9a091c, 0xffffffff},
292 {0x9a0968, 0x1a00},
293 {0x9a0920, 0xff},
294 {0x9a0918, 0x55555555},
295 {0x9a0920, 0x1ff},
296 {0x9a0918, 0x55555555},
297 {0x9a096c, 0x1a00},
298 {0x9a0924, 0xff},
299 {0x9a091c, 0x55555555},
300 {0x9a0924, 0x1ff},
301 {0x9a091c, 0x55555555},
302 {0x9a0968, 0x1b00},
303 {0x9a0920, 0x0},
304 {0x9a0918, 0xaaaaaaaa},
305 {0x9a0920, 0x100},
306 {0x9a0918, 0xaaaaaaaa},
307 {0x9a096c, 0x1b00},
308 {0x9a0924, 0x0},
309 {0x9a091c, 0xaaaaaaaa},
310 {0x9a0924, 0x100},
311 {0x9a091c, 0xaaaaaaaa},
312 {0x9a0968, 0x1c00},
313 {0x9a0920, 0xff},
314 {0x9a0918, 0x33333333},
315 {0x9a0920, 0x1ff},
316 {0x9a0918, 0x33333333},
317 {0x9a096c, 0x1c00},
318 {0x9a0924, 0xff},
319 {0x9a091c, 0x33333333},
320 {0x9a0924, 0x1ff},
321 {0x9a091c, 0x33333333},
322 {0x9a0968, 0x1d00},
323 {0x9a0920, 0x0},
324 {0x9a0918, 0xcccccccc},
325 {0x9a0920, 0x100},
326 {0x9a0918, 0xcccccccc},
327 {0x9a096c, 0x1d00},
328 {0x9a0924, 0x0},
329 {0x9a091c, 0xcccccccc},
330 {0x9a0924, 0x100},
331 {0x9a091c, 0xcccccccc},
332 {0x9a0968, 0x1e00},
333 {0x9a0920, 0x0},
334 {0x9a0918, 0xf0f0f0f0},
335 {0x9a0920, 0x100},
336 {0x9a0918, 0xf0f0f0f0},
337 {0x9a096c, 0x1e00},
338 {0x9a0924, 0x0},
339 {0x9a091c, 0xf0f0f0f0},
340 {0x9a0924, 0x100},
341 {0x9a091c, 0xf0f0f0f0},
342 {0x9a0968, 0x1f00},
343 {0x9a0920, 0xff},
344 {0x9a0918, 0xf0f0f0f},
345 {0x9a0920, 0x1ff},
346 {0x9a0918, 0xf0f0f0f},
347 {0x9a096c, 0x1f00},
348 {0x9a0924, 0xff},
349 {0x9a091c, 0xf0f0f0f},
350 {0x9a0924, 0x1ff},
351 {0x9a091c, 0xf0f0f0f},
352 {0x9a0968, 0x2000},
353 {0x9a0920, 0xff},
354 {0x9a0918, 0xff00ff},
355 {0x9a0920, 0x1ff},
356 {0x9a0918, 0xff00ff},
357 {0x9a096c, 0x2000},
358 {0x9a0924, 0xff},
359 {0x9a091c, 0xff00ff},
360 {0x9a0924, 0x1ff},
361 {0x9a091c, 0xff00ff},
362 {0x9a0968, 0x2100},
363 {0x9a0920, 0x0},
364 {0x9a0918, 0xff00ff00},
365 {0x9a0920, 0x100},
366 {0x9a0918, 0xff00ff00},
367 {0x9a096c, 0x2100},
368 {0x9a0924, 0x0},
369 {0x9a091c, 0xff00ff00},
370 {0x9a0924, 0x100},
371 {0x9a091c, 0xff00ff00},
372 {0x9a0968, 0x2200},
373 {0x9a0920, 0xff},
374 {0x9a0918, 0xffff},
375 {0x9a0920, 0x1ff},
376 {0x9a0918, 0xffff},
377 {0x9a096c, 0x2200},
378 {0x9a0924, 0xff},
379 {0x9a091c, 0xffff},
380 {0x9a0924, 0x1ff},
381 {0x9a091c, 0xffff},
382 {0x9a0968, 0x2300},
383 {0x9a0920, 0x0},
384 {0x9a0918, 0xffff0000},
385 {0x9a0920, 0x100},
386 {0x9a0918, 0xffff0000},
387 {0x9a096c, 0x2300},
388 {0x9a0924, 0x0},
389 {0x9a091c, 0xffff0000},
390 {0x9a0924, 0x100},
391 {0x9a091c, 0xffff0000},
392 {0x9a0968, 0x2400},
393 {0x9a0920, 0x0},
394 {0x9a0918, 0x0},
395 {0x9a0920, 0x100},
396 {0x9a0918, 0x0},
397 {0x9a096c, 0x2400},
398 {0x9a0924, 0x0},
399 {0x9a091c, 0x0},
400 {0x9a0924, 0x100},
401 {0x9a091c, 0x0},
402 {0x9a0968, 0x2500},
403 {0x9a0920, 0xff},
404 {0x9a0918, 0xffffffff},
405 {0x9a0920, 0x1ff},
406 {0x9a0918, 0xffffffff},
407 {0x9a096c, 0x2500},
408 {0x9a0924, 0xff},
409 {0x9a091c, 0xffffffff},
410 {0x9a0924, 0x1ff},
411 {0x9a091c, 0xffffffff},
412 {0x9a0968, 0x2600},
413 {0x9a0920, 0xff},
414 {0x9a0918, 0x55555555},
415 {0x9a0920, 0x1ff},
416 {0x9a0918, 0x55555555},
417 {0x9a096c, 0x2600},
418 {0x9a0924, 0xff},
419 {0x9a091c, 0x55555555},
420 {0x9a0924, 0x1ff},
421 {0x9a091c, 0x55555555},
422 {0x9a0968, 0x2700},
423 {0x9a0920, 0x0},
424 {0x9a0918, 0xaaaaaaaa},
425 {0x9a0920, 0x100},
426 {0x9a0918, 0xaaaaaaaa},
427 {0x9a096c, 0x2700},
428 {0x9a0924, 0x0},
429 {0x9a091c, 0xaaaaaaaa},
430 {0x9a0924, 0x100},
431 {0x9a091c, 0xaaaaaaaa},
432 {0x9a0968, 0x2800},
433 {0x9a0920, 0xff},
434 {0x9a0918, 0x33333333},
435 {0x9a0920, 0x1ff},
436 {0x9a0918, 0x33333333},
437 {0x9a096c, 0x2800},
438 {0x9a0924, 0xff},
439 {0x9a091c, 0x33333333},
440 {0x9a0924, 0x1ff},
441 {0x9a091c, 0x33333333},
442 {0x9a0968, 0x2900},
443 {0x9a0920, 0x0},
444 {0x9a0918, 0xcccccccc},
445 {0x9a0920, 0x100},
446 {0x9a0918, 0xcccccccc},
447 {0x9a096c, 0x2900},
448 {0x9a0924, 0x0},
449 {0x9a091c, 0xcccccccc},
450 {0x9a0924, 0x100},
451 {0x9a091c, 0xcccccccc},
452 {0x9a0968, 0x2a00},
453 {0x9a0920, 0x0},
454 {0x9a0918, 0xf0f0f0f0},
455 {0x9a0920, 0x100},
456 {0x9a0918, 0xf0f0f0f0},
457 {0x9a096c, 0x2a00},
458 {0x9a0924, 0x0},
459 {0x9a091c, 0xf0f0f0f0},
460 {0x9a0924, 0x100},
461 {0x9a091c, 0xf0f0f0f0},
462 {0x9a0968, 0x2b00},
463 {0x9a0920, 0xff},
464 {0x9a0918, 0xf0f0f0f},
465 {0x9a0920, 0x1ff},
466 {0x9a0918, 0xf0f0f0f},
467 {0x9a096c, 0x2b00},
468 {0x9a0924, 0xff},
469 {0x9a091c, 0xf0f0f0f},
470 {0x9a0924, 0x1ff},
471 {0x9a091c, 0xf0f0f0f},
472 {0x9a0968, 0x2c00},
473 {0x9a0920, 0xff},
474 {0x9a0918, 0xff00ff},
475 {0x9a0920, 0x1ff},
476 {0x9a0918, 0xff00ff},
477 {0x9a096c, 0x2c00},
478 {0x9a0924, 0xff},
479 {0x9a091c, 0xff00ff},
480 {0x9a0924, 0x1ff},
481 {0x9a091c, 0xff00ff},
482 {0x9a0968, 0x2d00},
483 {0x9a0920, 0x0},
484 {0x9a0918, 0xff00ff00},
485 {0x9a0920, 0x100},
486 {0x9a0918, 0xff00ff00},
487 {0x9a096c, 0x2d00},
488 {0x9a0924, 0x0},
489 {0x9a091c, 0xff00ff00},
490 {0x9a0924, 0x100},
491 {0x9a091c, 0xff00ff00},
492 {0x9a0968, 0x2e00},
493 {0x9a0920, 0xff},
494 {0x9a0918, 0xffff},
495 {0x9a0920, 0x1ff},
496 {0x9a0918, 0xffff},
497 {0x9a096c, 0x2e00},
498 {0x9a0924, 0xff},
499 {0x9a091c, 0xffff},
500 {0x9a0924, 0x1ff},
501 {0x9a091c, 0xffff},
502 {0x9a0968, 0x2f00},
503 {0x9a0920, 0x0},
504 {0x9a0918, 0xffff0000},
505 {0x9a0920, 0x100},
506 {0x9a0918, 0xffff0000},
507 {0x9a096c, 0x2f00},
508 {0x9a0924, 0x0},
509 {0x9a091c, 0xffff0000},
510 {0x9a0924, 0x100},
511 {0x9a091c, 0xffff0000},
512 {0x9a0968, 0x0},
513 {0x9a0900, 0x0},
514 {0x9a0968, 0x1},
515 {0x9a0900, 0xffffffff},
516 {0x9a0968, 0x2},
517 {0x9a0900, 0x0},
518 {0x9a0968, 0x3},
519 {0x9a0900, 0xffffffff},
520 {0x9a0968, 0x4},
521 {0x9a0900, 0x0},
522 {0x9a0968, 0x5},
523 {0x9a0900, 0xffffffff},
524 {0x9a0968, 0x6},
525 {0x9a0900, 0x0},
526 {0x9a0968, 0x7},
527 {0x9a0900, 0xffffffff},
528 {0x9a0968, 0x8},
529 {0x9a0900, 0x0},
530 {0x9a0968, 0x9},
531 {0x9a0900, 0xffffffff},
532 {0x9a0968, 0xa},
533 {0x9a0900, 0x0},
534 {0x9a0968, 0xb},
535 {0x9a0900, 0xffffffff},
536 {0x9a0968, 0xc},
537 {0x9a0900, 0x0},
538 {0x9a0968, 0xd},
539 {0x9a0900, 0xffffffff},
540 {0x9a0968, 0xe},
541 {0x9a0900, 0x0},
542 {0x9a0968, 0xf},
543 {0x9a0900, 0xffffffff},
544 {0x9a0968, 0x10},
545 {0x9a0900, 0x55555555},
546 {0x9a0968, 0x11},
547 {0x9a0900, 0xaaaaaaaa},
548 {0x9a0968, 0x12},
549 {0x9a0900, 0x55555555},
550 {0x9a0968, 0x13},
551 {0x9a0900, 0xaaaaaaaa},
552 {0x9a0968, 0x14},
553 {0x9a0900, 0x55555555},
554 {0x9a0968, 0x15},
555 {0x9a0900, 0xaaaaaaaa},
556 {0x9a0968, 0x16},
557 {0x9a0900, 0x55555555},
558 {0x9a0968, 0x17},
559 {0x9a0900, 0xaaaaaaaa},
560 {0x9a0968, 0x18},
561 {0x9a0900, 0x55555555},
562 {0x9a0968, 0x19},
563 {0x9a0900, 0xaaaaaaaa},
564 {0x9a0968, 0x1a},
565 {0x9a0900, 0x55555555},
566 {0x9a0968, 0x1b},
567 {0x9a0900, 0xaaaaaaaa},
568 {0x9a0968, 0x1c},
569 {0x9a0900, 0x55555555},
570 {0x9a0968, 0x1d},
571 {0x9a0900, 0xaaaaaaaa},
572 {0x9a0968, 0x1e},
573 {0x9a0900, 0x55555555},
574 {0x9a0968, 0x1f},
575 {0x9a0900, 0xaaaaaaaa},
576 {0x9a0968, 0x20},
577 {0x9a0900, 0xffff},
578 {0x9a0968, 0x21},
579 {0x9a0900, 0xffff0000},
580 {0x9a0968, 0x22},
581 {0x9a0900, 0xffff},
582 {0x9a0968, 0x23},
583 {0x9a0900, 0xffff0000},
584 {0x9a0968, 0x24},
585 {0x9a0900, 0xffff},
586 {0x9a0968, 0x25},
587 {0x9a0900, 0xffff0000},
588 {0x9a0968, 0x26},
589 {0x9a0900, 0xffff},
590 {0x9a0968, 0x27},
591 {0x9a0900, 0xffff0000},
592 {0x9a0968, 0x28},
593 {0x9a0900, 0xffff},
594 {0x9a0968, 0x29},
595 {0x9a0900, 0xffff0000},
596 {0x9a0968, 0x2a},
597 {0x9a0900, 0xffff},
598 {0x9a0968, 0x2b},
599 {0x9a0900, 0xffff0000},
600 {0x9a0968, 0x2c},
601 {0x9a0900, 0xffff},
602 {0x9a0968, 0x2d},
603 {0x9a0900, 0xffff0000},
604 {0x9a0968, 0x2e},
605 {0x9a0900, 0xffff},
606 {0x9a0968, 0x2f},
607 {0x9a0900, 0xffff0000},
608 {0x9a0968, 0x30},
609 {0x9a0900, 0xff00ff},
610 {0x9a0968, 0x31},
611 {0x9a0900, 0xff00ff00},
612 {0x9a0968, 0x32},
613 {0x9a0900, 0xff00ff},
614 {0x9a0968, 0x33},
615 {0x9a0900, 0xff00ff00},
616 {0x9a0968, 0x34},
617 {0x9a0900, 0xff00ff},
618 {0x9a0968, 0x35},
619 {0x9a0900, 0xff00ff00},
620 {0x9a0968, 0x36},
621 {0x9a0900, 0xff00ff},
622 {0x9a0968, 0x37},
623 {0x9a0900, 0xff00ff00},
624 {0x9a0968, 0x38},
625 {0x9a0900, 0xff00ff},
626 {0x9a0968, 0x39},
627 {0x9a0900, 0xff00ff00},
628 {0x9a0968, 0x3a},
629 {0x9a0900, 0xff00ff},
630 {0x9a0968, 0x3b},
631 {0x9a0900, 0xff00ff00},
632 {0x9a0968, 0x3c},
633 {0x9a0900, 0xff00ff},
634 {0x9a0968, 0x3d},
635 {0x9a0900, 0xff00ff00},
636 {0x9a0968, 0x3e},
637 {0x9a0900, 0xff00ff},
638 {0x9a0968, 0x3f},
639 {0x9a0900, 0xff00ff00},
640 {0x9a0968, 0x40},
641 {0x9a0900, 0x0},
642 {0x9a0968, 0x41},
643 {0x9a0900, 0xffffffff},
644 {0x9a0968, 0x42},
645 {0x9a0900, 0x0},
646 {0x9a0968, 0x43},
647 {0x9a0900, 0xffffffff},
648 {0x9a0968, 0x44},
649 {0x9a0900, 0x0},
650 {0x9a0968, 0x45},
651 {0x9a0900, 0xffffffff},
652 {0x9a0968, 0x46},
653 {0x9a0900, 0x0},
654 {0x9a0968, 0x47},
655 {0x9a0900, 0xffffffff},
656 {0x9a0968, 0x48},
657 {0x9a0900, 0x0},
658 {0x9a0968, 0x49},
659 {0x9a0900, 0xffffffff},
660 {0x9a0968, 0x4a},
661 {0x9a0900, 0x0},
662 {0x9a0968, 0x4b},
663 {0x9a0900, 0xffffffff},
664 {0x9a0968, 0x4c},
665 {0x9a0900, 0x0},
666 {0x9a0968, 0x4d},
667 {0x9a0900, 0xffffffff},
668 {0x9a0968, 0x4e},
669 {0x9a0900, 0x0},
670 {0x9a0968, 0x4f},
671 {0x9a0900, 0xffffffff},
672 {0x9a0968, 0x50},
673 {0x9a0900, 0x55555555},
674 {0x9a0968, 0x51},
675 {0x9a0900, 0xaaaaaaaa},
676 {0x9a0968, 0x52},
677 {0x9a0900, 0x55555555},
678 {0x9a0968, 0x53},
679 {0x9a0900, 0xaaaaaaaa},
680 {0x9a0968, 0x54},
681 {0x9a0900, 0x55555555},
682 {0x9a0968, 0x55},
683 {0x9a0900, 0xaaaaaaaa},
684 {0x9a0968, 0x56},
685 {0x9a0900, 0x55555555},
686 {0x9a0968, 0x57},
687 {0x9a0900, 0xaaaaaaaa},
688 {0x9a0968, 0x58},
689 {0x9a0900, 0x55555555},
690 {0x9a0968, 0x59},
691 {0x9a0900, 0xaaaaaaaa},
692 {0x9a0968, 0x5a},
693 {0x9a0900, 0x55555555},
694 {0x9a0968, 0x5b},
695 {0x9a0900, 0xaaaaaaaa},
696 {0x9a0968, 0x5c},
697 {0x9a0900, 0x55555555},
698 {0x9a0968, 0x5d},
699 {0x9a0900, 0xaaaaaaaa},
700 {0x9a0968, 0x5e},
701 {0x9a0900, 0x55555555},
702 {0x9a0968, 0x5f},
703 {0x9a0900, 0x0},
704 {0x9a0968, 0x60},
705 {0x9a0900, 0xffffffff},
706 {0x9a0968, 0x61},
707 {0x9a0900, 0x0},
708 {0x9a0968, 0x62},
709 {0x9a0900, 0xffffffff},
710 {0x9a0968, 0x63},
711 {0x9a0900, 0x0},
712 {0x9a0968, 0x64},
713 {0x9a0900, 0xffffffff},
714 {0x9a0968, 0x65},
715 {0x9a0900, 0x0},
716 {0x9a0968, 0x66},
717 {0x9a0900, 0xffffffff},
718 {0x9a0968, 0x67},
719 {0x9a0900, 0x0},
720 {0x9a0968, 0x68},
721 {0x9a0900, 0xffffffff},
722 {0x9a0968, 0x69},
723 {0x9a0900, 0x0},
724 {0x9a0968, 0x6a},
725 {0x9a0900, 0xffffffff},
726 {0x9a0968, 0x6b},
727 {0x9a0900, 0x0},
728 {0x9a0968, 0x6c},
729 {0x9a0900, 0xffffffff},
730 {0x9a0968, 0x6d},
731 {0x9a0900, 0x0},
732 {0x9a0968, 0x6e},
733 {0x9a0900, 0xffffffff},
734 {0x9a0968, 0x6f},
735 {0x9a0900, 0x55555555},
736 {0x9a0968, 0x70},
737 {0x9a0900, 0xaaaaaaaa},
738 {0x9a0968, 0x71},
739 {0x9a0900, 0x55555555},
740 {0x9a0968, 0x72},
741 {0x9a0900, 0xaaaaaaaa},
742 {0x9a0968, 0x73},
743 {0x9a0900, 0x55555555},
744 {0x9a0968, 0x74},
745 {0x9a0900, 0xaaaaaaaa},
746 {0x9a0968, 0x75},
747 {0x9a0900, 0x55555555},
748 {0x9a0968, 0x76},
749 {0x9a0900, 0xaaaaaaaa},
750 {0x9a0968, 0x77},
751 {0x9a0900, 0x55555555},
752 {0x9a0968, 0x78},
753 {0x9a0900, 0xaaaaaaaa},
754 {0x9a0968, 0x79},
755 {0x9a0900, 0x55555555},
756 {0x9a0968, 0x7a},
757 {0x9a0900, 0xaaaaaaaa},
758 {0x9a0968, 0x7b},
759 {0x9a0900, 0x55555555},
760 {0x9a0968, 0x7c},
761 {0x9a0900, 0xaaaaaaaa},
762 {0x9a0968, 0x7d},
763 {0x9a0900, 0x55555555},
764 {0x9a0968, 0x7e},
765 {0x9a0900, 0xaaaaaaaa},
766 {0x9a0968, 0x7f},
767 {0x9a0900, 0xffff},
768 {0x9a0968, 0x80},
769 {0x9a0900, 0xffff0000},
770 {0x9a0968, 0x81},
771 {0x9a0900, 0xffff},
772 {0x9a0968, 0x82},
773 {0x9a0900, 0xffff0000},
774 {0x9a0968, 0x83},
775 {0x9a0900, 0xffff},
776 {0x9a0968, 0x84},
777 {0x9a0900, 0xffff0000},
778 {0x9a0968, 0x85},
779 {0x9a0900, 0xffff},
780 {0x9a0968, 0x86},
781 {0x9a0900, 0xffff0000},
782 {0x9a0968, 0x87},
783 {0x9a0900, 0xffff},
784 {0x9a0968, 0x88},
785 {0x9a0900, 0xffff0000},
786 {0x9a0968, 0x89},
787 {0x9a0900, 0xffff},
788 {0x9a0968, 0x8a},
789 {0x9a0900, 0xffff0000},
790 {0x9a0968, 0x8b},
791 {0x9a0900, 0xffff},
792 {0x9a0968, 0x8c},
793 {0x9a0900, 0xffff0000},
794 {0x9a0968, 0x8d},
795 {0x9a0900, 0xffff},
796 {0x9a0968, 0x8e},
797 {0x9a0900, 0xffff0000},
798 {0x9a0968, 0x8f},
799 {0x9a0900, 0xff00ff},
800 {0x9a0968, 0x90},
801 {0x9a0900, 0xff00ff00},
802 {0x9a0968, 0x91},
803 {0x9a0900, 0xff00ff},
804 {0x9a0968, 0x92},
805 {0x9a0900, 0xff00ff00},
806 {0x9a0968, 0x93},
807 {0x9a0900, 0xff00ff},
808 {0x9a0968, 0x94},
809 {0x9a0900, 0xff00ff00},
810 {0x9a0968, 0x95},
811 {0x9a0900, 0xff00ff},
812 {0x9a0968, 0x96},
813 {0x9a0900, 0xff00ff00},
814 {0x9a0968, 0x97},
815 {0x9a0900, 0xff00ff},
816 {0x9a0968, 0x98},
817 {0x9a0900, 0xff00ff00},
818 {0x9a0968, 0x99},
819 {0x9a0900, 0xff00ff},
820 {0x9a0968, 0x9a},
821 {0x9a0900, 0xff00ff00},
822 {0x9a0968, 0x9b},
823 {0x9a0900, 0xff00ff},
824 {0x9a0968, 0x9c},
825 {0x9a0900, 0xff00ff00},
826 {0x9a0968, 0x9d},
827 {0x9a0900, 0xff00ff},
828 {0x9a0968, 0x9e},
829 {0x9a0900, 0xff00ff00},
830 {0x9a0968, 0x9f},
831 {0x9a0900, 0x0},
832 {0x9a0968, 0xa0},
833 {0x9a0900, 0xffffffff},
834 {0x9a0968, 0xa1},
835 {0x9a0900, 0x0},
836 {0x9a0968, 0xa2},
837 {0x9a0900, 0xffffffff},
838 {0x9a0968, 0xa3},
839 {0x9a0900, 0x0},
840 {0x9a0968, 0xa4},
841 {0x9a0900, 0xffffffff},
842 {0x9a0968, 0xa5},
843 {0x9a0900, 0x0},
844 {0x9a0968, 0xa6},
845 {0x9a0900, 0xffffffff},
846 {0x9a0968, 0xa7},
847 {0x9a0900, 0x0},
848 {0x9a0968, 0xa8},
849 {0x9a0900, 0xffffffff},
850 {0x9a0968, 0xa9},
851 {0x9a0900, 0x0},
852 {0x9a0968, 0xaa},
853 {0x9a0900, 0xffffffff},
854 {0x9a0968, 0xab},
855 {0x9a0900, 0x0},
856 {0x9a0968, 0xac},
857 {0x9a0900, 0xffffffff},
858 {0x9a0968, 0xad},
859 {0x9a0900, 0x0},
860 {0x9a0968, 0xae},
861 {0x9a0900, 0xffffffff},
862 {0x9a0968, 0xaf},
863 {0x9a0900, 0x55555555},
864 {0x9a0968, 0xb0},
865 {0x9a0900, 0xaaaaaaaa},
866 {0x9a0968, 0xb1},
867 {0x9a0900, 0x55555555},
868 {0x9a0968, 0xb2},
869 {0x9a0900, 0xaaaaaaaa},
870 {0x9a0968, 0xb3},
871 {0x9a0900, 0x55555555},
872 {0x9a0968, 0xb4},
873 {0x9a0900, 0xaaaaaaaa},
874 {0x9a0968, 0xb5},
875 {0x9a0900, 0x55555555},
876 {0x9a0968, 0xb6},
877 {0x9a0900, 0xaaaaaaaa},
878 {0x9a0968, 0xb7},
879 {0x9a0900, 0x55555555},
880 {0x9a0968, 0xb8},
881 {0x9a0900, 0xaaaaaaaa},
882 {0x9a0968, 0xb9},
883 {0x9a0900, 0x55555555},
884 {0x9a0968, 0xba},
885 {0x9a0900, 0xaaaaaaaa},
886 {0x9a0968, 0xbb},
887 {0x9a0900, 0x55555555},
888 {0x9a0968, 0xbc},
889 {0x9a0900, 0xaaaaaaaa},
890 {0x9a0968, 0xbd},
891 {0x9a0900, 0x55555555},
892 {0x9a0968, 0xbe},
893 {0x9a0900, 0x0},
894 {0x9a0968, 0xbf},
895 {0x9a0900, 0xffffffff},
896 {0x9a0968, 0xc0},
897 {0x9a0900, 0x0},
898 {0x9a0968, 0xc1},
899 {0x9a0900, 0xffffffff},
900 {0x9a0968, 0xc2},
901 {0x9a0900, 0x0},
902 {0x9a0968, 0xc3},
903 {0x9a0900, 0xffffffff},
904 {0x9a0968, 0xc4},
905 {0x9a0900, 0x0},
906 {0x9a0968, 0xc5},
907 {0x9a0900, 0xffffffff},
908 {0x9a0968, 0xc6},
909 {0x9a0900, 0x0},
910 {0x9a0968, 0xc7},
911 {0x9a0900, 0xffffffff},
912 {0x9a0968, 0xc8},
913 {0x9a0900, 0x0},
914 {0x9a0968, 0xc9},
915 {0x9a0900, 0xffffffff},
916 {0x9a0968, 0xca},
917 {0x9a0900, 0x0},
918 {0x9a0968, 0xcb},
919 {0x9a0900, 0xffffffff},
920 {0x9a0968, 0xcc},
921 {0x9a0900, 0x0},
922 {0x9a0968, 0xcd},
923 {0x9a0900, 0xffffffff},
924 {0x9a0968, 0xce},
925 {0x9a0900, 0x55555555},
926 {0x9a0968, 0xcf},
927 {0x9a0900, 0xaaaaaaaa},
928 {0x9a0968, 0xd0},
929 {0x9a0900, 0x55555555},
930 {0x9a0968, 0xd1},
931 {0x9a0900, 0xaaaaaaaa},
932 {0x9a0968, 0xd2},
933 {0x9a0900, 0x55555555},
934 {0x9a0968, 0xd3},
935 {0x9a0900, 0xaaaaaaaa},
936 {0x9a0968, 0xd4},
937 {0x9a0900, 0x55555555},
938 {0x9a0968, 0xd5},
939 {0x9a0900, 0xaaaaaaaa},
940 {0x9a0968, 0xd6},
941 {0x9a0900, 0x55555555},
942 {0x9a0968, 0xd7},
943 {0x9a0900, 0xaaaaaaaa},
944 {0x9a0968, 0xd8},
945 {0x9a0900, 0x55555555},
946 {0x9a0968, 0xd9},
947 {0x9a0900, 0xaaaaaaaa},
948 {0x9a0968, 0xda},
949 {0x9a0900, 0x55555555},
950 {0x9a0968, 0xdb},
951 {0x9a0900, 0xaaaaaaaa},
952 {0x9a0968, 0xdc},
953 {0x9a0900, 0x55555555},
954 {0x9a0968, 0xdd},
955 {0x9a0900, 0xaaaaaaaa},
956 {0x9a0968, 0xde},
957 {0x9a0900, 0xffff},
958 {0x9a0968, 0xdf},
959 {0x9a0900, 0xffff0000},
960 {0x9a0968, 0xe0},
961 {0x9a0900, 0xffff},
962 {0x9a0968, 0xe1},
963 {0x9a0900, 0xffff0000},
964 {0x9a0968, 0xe2},
965 {0x9a0900, 0xffff},
966 {0x9a0968, 0xe3},
967 {0x9a0900, 0xffff0000},
968 {0x9a0968, 0xe4},
969 {0x9a0900, 0xffff},
970 {0x9a0968, 0xe5},
971 {0x9a0900, 0xffff0000},
972 {0x9a0968, 0xe6},
973 {0x9a0900, 0xffff},
974 {0x9a0968, 0xe7},
975 {0x9a0900, 0xffff0000},
976 {0x9a0968, 0xe8},
977 {0x9a0900, 0xffff},
978 {0x9a0968, 0xe9},
979 {0x9a0900, 0xffff0000},
980 {0x9a0968, 0xea},
981 {0x9a0900, 0xffff},
982 {0x9a0968, 0xeb},
983 {0x9a0900, 0xffff0000},
984 {0x9a0968, 0xec},
985 {0x9a0900, 0xffff},
986 {0x9a0968, 0xed},
987 {0x9a0900, 0xffff0000},
988 {0x9a0968, 0xee},
989 {0x9a0900, 0xff00ff},
990 {0x9a0968, 0xef},
991 {0x9a0900, 0xff00ff00},
992 {0x9a0968, 0xf0},
993 {0x9a0900, 0xff00ff},
994 {0x9a0968, 0xf1},
995 {0x9a0900, 0xff00ff00},
996 {0x9a0968, 0xf2},
997 {0x9a0900, 0xff00ff},
998 {0x9a0968, 0xf3},
999 {0x9a0900, 0xff00ff00},
1000 {0x9a0968, 0xf4},
1001 {0x9a0900, 0xff00ff},
1002 {0x9a0968, 0xf5},
1003 {0x9a0900, 0xff00ff00},
1004 {0x9a0968, 0xf6},
1005 {0x9a0900, 0xff00ff},
1006 {0x9a0968, 0xf7},
1007 {0x9a0900, 0xff00ff00},
1008 {0x9a0968, 0xf8},
1009 {0x9a0900, 0xff00ff},
1010 {0x9a0968, 0xf9},
1011 {0x9a0900, 0xff00ff00},
1012 {0x9a0968, 0xfa},
1013 {0x9a0900, 0xff00ff},
1014 {0x9a0968, 0xfb},
1015 {0x9a0900, 0xff00ff00},
1016 {0x9a0968, 0xfc},
1017 {0x9a0900, 0xff00ff},
1018 {0x9a0968, 0xfd},
1019 {0x9a0900, 0xff00ff00},
1020 {0x9a0968, 0xfe},
1021 {0x9a0900, 0x0},
1022 {0x9a0968, 0xff},
1023 {0x9a0900, 0xffffffff},
1024 {0x9a096c, 0x0},
1025 {0x9a0904, 0x0},
1026 {0x9a096c, 0x1},
1027 {0x9a0904, 0xffffffff},
1028 {0x9a096c, 0x2},
1029 {0x9a0904, 0x0},
1030 {0x9a096c, 0x3},
1031 {0x9a0904, 0xffffffff},
1032 {0x9a096c, 0x4},
1033 {0x9a0904, 0x0},
1034 {0x9a096c, 0x5},
1035 {0x9a0904, 0xffffffff},
1036 {0x9a096c, 0x6},
1037 {0x9a0904, 0x0},
1038 {0x9a096c, 0x7},
1039 {0x9a0904, 0xffffffff},
1040 {0x9a096c, 0x8},
1041 {0x9a0904, 0x0},
1042 {0x9a096c, 0x9},
1043 {0x9a0904, 0xffffffff},
1044 {0x9a096c, 0xa},
1045 {0x9a0904, 0x0},
1046 {0x9a096c, 0xb},
1047 {0x9a0904, 0xffffffff},
1048 {0x9a096c, 0xc},
1049 {0x9a0904, 0x0},
1050 {0x9a096c, 0xd},
1051 {0x9a0904, 0xffffffff},
1052 {0x9a096c, 0xe},
1053 {0x9a0904, 0x0},
1054 {0x9a096c, 0xf},
1055 {0x9a0904, 0xffffffff},
1056 {0x9a096c, 0x10},
1057 {0x9a0904, 0x55555555},
1058 {0x9a096c, 0x11},
1059 {0x9a0904, 0xaaaaaaaa},
1060 {0x9a096c, 0x12},
1061 {0x9a0904, 0x55555555},
1062 {0x9a096c, 0x13},
1063 {0x9a0904, 0xaaaaaaaa},
1064 {0x9a096c, 0x14},
1065 {0x9a0904, 0x55555555},
1066 {0x9a096c, 0x15},
1067 {0x9a0904, 0xaaaaaaaa},
1068 {0x9a096c, 0x16},
1069 {0x9a0904, 0x55555555},
1070 {0x9a096c, 0x17},
1071 {0x9a0904, 0xaaaaaaaa},
1072 {0x9a096c, 0x18},
1073 {0x9a0904, 0x55555555},
1074 {0x9a096c, 0x19},
1075 {0x9a0904, 0xaaaaaaaa},
1076 {0x9a096c, 0x1a},
1077 {0x9a0904, 0x55555555},
1078 {0x9a096c, 0x1b},
1079 {0x9a0904, 0xaaaaaaaa},
1080 {0x9a096c, 0x1c},
1081 {0x9a0904, 0x55555555},
1082 {0x9a096c, 0x1d},
1083 {0x9a0904, 0xaaaaaaaa},
1084 {0x9a096c, 0x1e},
1085 {0x9a0904, 0x55555555},
1086 {0x9a096c, 0x1f},
1087 {0x9a0904, 0xaaaaaaaa},
1088 {0x9a096c, 0x20},
1089 {0x9a0904, 0xffff},
1090 {0x9a096c, 0x21},
1091 {0x9a0904, 0xffff0000},
1092 {0x9a096c, 0x22},
1093 {0x9a0904, 0xffff},
1094 {0x9a096c, 0x23},
1095 {0x9a0904, 0xffff0000},
1096 {0x9a096c, 0x24},
1097 {0x9a0904, 0xffff},
1098 {0x9a096c, 0x25},
1099 {0x9a0904, 0xffff0000},
1100 {0x9a096c, 0x26},
1101 {0x9a0904, 0xffff},
1102 {0x9a096c, 0x27},
1103 {0x9a0904, 0xffff0000},
1104 {0x9a096c, 0x28},
1105 {0x9a0904, 0xffff},
1106 {0x9a096c, 0x29},
1107 {0x9a0904, 0xffff0000},
1108 {0x9a096c, 0x2a},
1109 {0x9a0904, 0xffff},
1110 {0x9a096c, 0x2b},
1111 {0x9a0904, 0xffff0000},
1112 {0x9a096c, 0x2c},
1113 {0x9a0904, 0xffff},
1114 {0x9a096c, 0x2d},
1115 {0x9a0904, 0xffff0000},
1116 {0x9a096c, 0x2e},
1117 {0x9a0904, 0xffff},
1118 {0x9a096c, 0x2f},
1119 {0x9a0904, 0xffff0000},
1120 {0x9a096c, 0x30},
1121 {0x9a0904, 0xff00ff},
1122 {0x9a096c, 0x31},
1123 {0x9a0904, 0xff00ff00},
1124 {0x9a096c, 0x32},
1125 {0x9a0904, 0xff00ff},
1126 {0x9a096c, 0x33},
1127 {0x9a0904, 0xff00ff00},
1128 {0x9a096c, 0x34},
1129 {0x9a0904, 0xff00ff},
1130 {0x9a096c, 0x35},
1131 {0x9a0904, 0xff00ff00},
1132 {0x9a096c, 0x36},
1133 {0x9a0904, 0xff00ff},
1134 {0x9a096c, 0x37},
1135 {0x9a0904, 0xff00ff00},
1136 {0x9a096c, 0x38},
1137 {0x9a0904, 0xff00ff},
1138 {0x9a096c, 0x39},
1139 {0x9a0904, 0xff00ff00},
1140 {0x9a096c, 0x3a},
1141 {0x9a0904, 0xff00ff},
1142 {0x9a096c, 0x3b},
1143 {0x9a0904, 0xff00ff00},
1144 {0x9a096c, 0x3c},
1145 {0x9a0904, 0xff00ff},
1146 {0x9a096c, 0x3d},
1147 {0x9a0904, 0xff00ff00},
1148 {0x9a096c, 0x3e},
1149 {0x9a0904, 0xff00ff},
1150 {0x9a096c, 0x3f},
1151 {0x9a0904, 0xff00ff00},
1152 {0x9a096c, 0x40},
1153 {0x9a0904, 0x0},
1154 {0x9a096c, 0x41},
1155 {0x9a0904, 0xffffffff},
1156 {0x9a096c, 0x42},
1157 {0x9a0904, 0x0},
1158 {0x9a096c, 0x43},
1159 {0x9a0904, 0xffffffff},
1160 {0x9a096c, 0x44},
1161 {0x9a0904, 0x0},
1162 {0x9a096c, 0x45},
1163 {0x9a0904, 0xffffffff},
1164 {0x9a096c, 0x46},
1165 {0x9a0904, 0x0},
1166 {0x9a096c, 0x47},
1167 {0x9a0904, 0xffffffff},
1168 {0x9a096c, 0x48},
1169 {0x9a0904, 0x0},
1170 {0x9a096c, 0x49},
1171 {0x9a0904, 0xffffffff},
1172 {0x9a096c, 0x4a},
1173 {0x9a0904, 0x0},
1174 {0x9a096c, 0x4b},
1175 {0x9a0904, 0xffffffff},
1176 {0x9a096c, 0x4c},
1177 {0x9a0904, 0x0},
1178 {0x9a096c, 0x4d},
1179 {0x9a0904, 0xffffffff},
1180 {0x9a096c, 0x4e},
1181 {0x9a0904, 0x0},
1182 {0x9a096c, 0x4f},
1183 {0x9a0904, 0xffffffff},
1184 {0x9a096c, 0x50},
1185 {0x9a0904, 0x55555555},
1186 {0x9a096c, 0x51},
1187 {0x9a0904, 0xaaaaaaaa},
1188 {0x9a096c, 0x52},
1189 {0x9a0904, 0x55555555},
1190 {0x9a096c, 0x53},
1191 {0x9a0904, 0xaaaaaaaa},
1192 {0x9a096c, 0x54},
1193 {0x9a0904, 0x55555555},
1194 {0x9a096c, 0x55},
1195 {0x9a0904, 0xaaaaaaaa},
1196 {0x9a096c, 0x56},
1197 {0x9a0904, 0x55555555},
1198 {0x9a096c, 0x57},
1199 {0x9a0904, 0xaaaaaaaa},
1200 {0x9a096c, 0x58},
1201 {0x9a0904, 0x55555555},
1202 {0x9a096c, 0x59},
1203 {0x9a0904, 0xaaaaaaaa},
1204 {0x9a096c, 0x5a},
1205 {0x9a0904, 0x55555555},
1206 {0x9a096c, 0x5b},
1207 {0x9a0904, 0xaaaaaaaa},
1208 {0x9a096c, 0x5c},
1209 {0x9a0904, 0x55555555},
1210 {0x9a096c, 0x5d},
1211 {0x9a0904, 0xaaaaaaaa},
1212 {0x9a096c, 0x5e},
1213 {0x9a0904, 0x55555555},
1214 {0x9a096c, 0x5f},
1215 {0x9a0904, 0x0},
1216 {0x9a096c, 0x60},
1217 {0x9a0904, 0xffffffff},
1218 {0x9a096c, 0x61},
1219 {0x9a0904, 0x0},
1220 {0x9a096c, 0x62},
1221 {0x9a0904, 0xffffffff},
1222 {0x9a096c, 0x63},
1223 {0x9a0904, 0x0},
1224 {0x9a096c, 0x64},
1225 {0x9a0904, 0xffffffff},
1226 {0x9a096c, 0x65},
1227 {0x9a0904, 0x0},
1228 {0x9a096c, 0x66},
1229 {0x9a0904, 0xffffffff},
1230 {0x9a096c, 0x67},
1231 {0x9a0904, 0x0},
1232 {0x9a096c, 0x68},
1233 {0x9a0904, 0xffffffff},
1234 {0x9a096c, 0x69},
1235 {0x9a0904, 0x0},
1236 {0x9a096c, 0x6a},
1237 {0x9a0904, 0xffffffff},
1238 {0x9a096c, 0x6b},
1239 {0x9a0904, 0x0},
1240 {0x9a096c, 0x6c},
1241 {0x9a0904, 0xffffffff},
1242 {0x9a096c, 0x6d},
1243 {0x9a0904, 0x0},
1244 {0x9a096c, 0x6e},
1245 {0x9a0904, 0xffffffff},
1246 {0x9a096c, 0x6f},
1247 {0x9a0904, 0x55555555},
1248 {0x9a096c, 0x70},
1249 {0x9a0904, 0xaaaaaaaa},
1250 {0x9a096c, 0x71},
1251 {0x9a0904, 0x55555555},
1252 {0x9a096c, 0x72},
1253 {0x9a0904, 0xaaaaaaaa},
1254 {0x9a096c, 0x73},
1255 {0x9a0904, 0x55555555},
1256 {0x9a096c, 0x74},
1257 {0x9a0904, 0xaaaaaaaa},
1258 {0x9a096c, 0x75},
1259 {0x9a0904, 0x55555555},
1260 {0x9a096c, 0x76},
1261 {0x9a0904, 0xaaaaaaaa},
1262 {0x9a096c, 0x77},
1263 {0x9a0904, 0x55555555},
1264 {0x9a096c, 0x78},
1265 {0x9a0904, 0xaaaaaaaa},
1266 {0x9a096c, 0x79},
1267 {0x9a0904, 0x55555555},
1268 {0x9a096c, 0x7a},
1269 {0x9a0904, 0xaaaaaaaa},
1270 {0x9a096c, 0x7b},
1271 {0x9a0904, 0x55555555},
1272 {0x9a096c, 0x7c},
1273 {0x9a0904, 0xaaaaaaaa},
1274 {0x9a096c, 0x7d},
1275 {0x9a0904, 0x55555555},
1276 {0x9a096c, 0x7e},
1277 {0x9a0904, 0xaaaaaaaa},
1278 {0x9a096c, 0x7f},
1279 {0x9a0904, 0xffff},
1280 {0x9a096c, 0x80},
1281 {0x9a0904, 0xffff0000},
1282 {0x9a096c, 0x81},
1283 {0x9a0904, 0xffff},
1284 {0x9a096c, 0x82},
1285 {0x9a0904, 0xffff0000},
1286 {0x9a096c, 0x83},
1287 {0x9a0904, 0xffff},
1288 {0x9a096c, 0x84},
1289 {0x9a0904, 0xffff0000},
1290 {0x9a096c, 0x85},
1291 {0x9a0904, 0xffff},
1292 {0x9a096c, 0x86},
1293 {0x9a0904, 0xffff0000},
1294 {0x9a096c, 0x87},
1295 {0x9a0904, 0xffff},
1296 {0x9a096c, 0x88},
1297 {0x9a0904, 0xffff0000},
1298 {0x9a096c, 0x89},
1299 {0x9a0904, 0xffff},
1300 {0x9a096c, 0x8a},
1301 {0x9a0904, 0xffff0000},
1302 {0x9a096c, 0x8b},
1303 {0x9a0904, 0xffff},
1304 {0x9a096c, 0x8c},
1305 {0x9a0904, 0xffff0000},
1306 {0x9a096c, 0x8d},
1307 {0x9a0904, 0xffff},
1308 {0x9a096c, 0x8e},
1309 {0x9a0904, 0xffff0000},
1310 {0x9a096c, 0x8f},
1311 {0x9a0904, 0xff00ff},
1312 {0x9a096c, 0x90},
1313 {0x9a0904, 0xff00ff00},
1314 {0x9a096c, 0x91},
1315 {0x9a0904, 0xff00ff},
1316 {0x9a096c, 0x92},
1317 {0x9a0904, 0xff00ff00},
1318 {0x9a096c, 0x93},
1319 {0x9a0904, 0xff00ff},
1320 {0x9a096c, 0x94},
1321 {0x9a0904, 0xff00ff00},
1322 {0x9a096c, 0x95},
1323 {0x9a0904, 0xff00ff},
1324 {0x9a096c, 0x96},
1325 {0x9a0904, 0xff00ff00},
1326 {0x9a096c, 0x97},
1327 {0x9a0904, 0xff00ff},
1328 {0x9a096c, 0x98},
1329 {0x9a0904, 0xff00ff00},
1330 {0x9a096c, 0x99},
1331 {0x9a0904, 0xff00ff},
1332 {0x9a096c, 0x9a},
1333 {0x9a0904, 0xff00ff00},
1334 {0x9a096c, 0x9b},
1335 {0x9a0904, 0xff00ff},
1336 {0x9a096c, 0x9c},
1337 {0x9a0904, 0xff00ff00},
1338 {0x9a096c, 0x9d},
1339 {0x9a0904, 0xff00ff},
1340 {0x9a096c, 0x9e},
1341 {0x9a0904, 0xff00ff00},
1342 {0x9a096c, 0x9f},
1343 {0x9a0904, 0x0},
1344 {0x9a096c, 0xa0},
1345 {0x9a0904, 0xffffffff},
1346 {0x9a096c, 0xa1},
1347 {0x9a0904, 0x0},
1348 {0x9a096c, 0xa2},
1349 {0x9a0904, 0xffffffff},
1350 {0x9a096c, 0xa3},
1351 {0x9a0904, 0x0},
1352 {0x9a096c, 0xa4},
1353 {0x9a0904, 0xffffffff},
1354 {0x9a096c, 0xa5},
1355 {0x9a0904, 0x0},
1356 {0x9a096c, 0xa6},
1357 {0x9a0904, 0xffffffff},
1358 {0x9a096c, 0xa7},
1359 {0x9a0904, 0x0},
1360 {0x9a096c, 0xa8},
1361 {0x9a0904, 0xffffffff},
1362 {0x9a096c, 0xa9},
1363 {0x9a0904, 0x0},
1364 {0x9a096c, 0xaa},
1365 {0x9a0904, 0xffffffff},
1366 {0x9a096c, 0xab},
1367 {0x9a0904, 0x0},
1368 {0x9a096c, 0xac},
1369 {0x9a0904, 0xffffffff},
1370 {0x9a096c, 0xad},
1371 {0x9a0904, 0x0},
1372 {0x9a096c, 0xae},
1373 {0x9a0904, 0xffffffff},
1374 {0x9a096c, 0xaf},
1375 {0x9a0904, 0x55555555},
1376 {0x9a096c, 0xb0},
1377 {0x9a0904, 0xaaaaaaaa},
1378 {0x9a096c, 0xb1},
1379 {0x9a0904, 0x55555555},
1380 {0x9a096c, 0xb2},
1381 {0x9a0904, 0xaaaaaaaa},
1382 {0x9a096c, 0xb3},
1383 {0x9a0904, 0x55555555},
1384 {0x9a096c, 0xb4},
1385 {0x9a0904, 0xaaaaaaaa},
1386 {0x9a096c, 0xb5},
1387 {0x9a0904, 0x55555555},
1388 {0x9a096c, 0xb6},
1389 {0x9a0904, 0xaaaaaaaa},
1390 {0x9a096c, 0xb7},
1391 {0x9a0904, 0x55555555},
1392 {0x9a096c, 0xb8},
1393 {0x9a0904, 0xaaaaaaaa},
1394 {0x9a096c, 0xb9},
1395 {0x9a0904, 0x55555555},
1396 {0x9a096c, 0xba},
1397 {0x9a0904, 0xaaaaaaaa},
1398 {0x9a096c, 0xbb},
1399 {0x9a0904, 0x55555555},
1400 {0x9a096c, 0xbc},
1401 {0x9a0904, 0xaaaaaaaa},
1402 {0x9a096c, 0xbd},
1403 {0x9a0904, 0x55555555},
1404 {0x9a096c, 0xbe},
1405 {0x9a0904, 0x0},
1406 {0x9a096c, 0xbf},
1407 {0x9a0904, 0xffffffff},
1408 {0x9a096c, 0xc0},
1409 {0x9a0904, 0x0},
1410 {0x9a096c, 0xc1},
1411 {0x9a0904, 0xffffffff},
1412 {0x9a096c, 0xc2},
1413 {0x9a0904, 0x0},
1414 {0x9a096c, 0xc3},
1415 {0x9a0904, 0xffffffff},
1416 {0x9a096c, 0xc4},
1417 {0x9a0904, 0x0},
1418 {0x9a096c, 0xc5},
1419 {0x9a0904, 0xffffffff},
1420 {0x9a096c, 0xc6},
1421 {0x9a0904, 0x0},
1422 {0x9a096c, 0xc7},
1423 {0x9a0904, 0xffffffff},
1424 {0x9a096c, 0xc8},
1425 {0x9a0904, 0x0},
1426 {0x9a096c, 0xc9},
1427 {0x9a0904, 0xffffffff},
1428 {0x9a096c, 0xca},
1429 {0x9a0904, 0x0},
1430 {0x9a096c, 0xcb},
1431 {0x9a0904, 0xffffffff},
1432 {0x9a096c, 0xcc},
1433 {0x9a0904, 0x0},
1434 {0x9a096c, 0xcd},
1435 {0x9a0904, 0xffffffff},
1436 {0x9a096c, 0xce},
1437 {0x9a0904, 0x55555555},
1438 {0x9a096c, 0xcf},
1439 {0x9a0904, 0xaaaaaaaa},
1440 {0x9a096c, 0xd0},
1441 {0x9a0904, 0x55555555},
1442 {0x9a096c, 0xd1},
1443 {0x9a0904, 0xaaaaaaaa},
1444 {0x9a096c, 0xd2},
1445 {0x9a0904, 0x55555555},
1446 {0x9a096c, 0xd3},
1447 {0x9a0904, 0xaaaaaaaa},
1448 {0x9a096c, 0xd4},
1449 {0x9a0904, 0x55555555},
1450 {0x9a096c, 0xd5},
1451 {0x9a0904, 0xaaaaaaaa},
1452 {0x9a096c, 0xd6},
1453 {0x9a0904, 0x55555555},
1454 {0x9a096c, 0xd7},
1455 {0x9a0904, 0xaaaaaaaa},
1456 {0x9a096c, 0xd8},
1457 {0x9a0904, 0x55555555},
1458 {0x9a096c, 0xd9},
1459 {0x9a0904, 0xaaaaaaaa},
1460 {0x9a096c, 0xda},
1461 {0x9a0904, 0x55555555},
1462 {0x9a096c, 0xdb},
1463 {0x9a0904, 0xaaaaaaaa},
1464 {0x9a096c, 0xdc},
1465 {0x9a0904, 0x55555555},
1466 {0x9a096c, 0xdd},
1467 {0x9a0904, 0xaaaaaaaa},
1468 {0x9a096c, 0xde},
1469 {0x9a0904, 0xffff},
1470 {0x9a096c, 0xdf},
1471 {0x9a0904, 0xffff0000},
1472 {0x9a096c, 0xe0},
1473 {0x9a0904, 0xffff},
1474 {0x9a096c, 0xe1},
1475 {0x9a0904, 0xffff0000},
1476 {0x9a096c, 0xe2},
1477 {0x9a0904, 0xffff},
1478 {0x9a096c, 0xe3},
1479 {0x9a0904, 0xffff0000},
1480 {0x9a096c, 0xe4},
1481 {0x9a0904, 0xffff},
1482 {0x9a096c, 0xe5},
1483 {0x9a0904, 0xffff0000},
1484 {0x9a096c, 0xe6},
1485 {0x9a0904, 0xffff},
1486 {0x9a096c, 0xe7},
1487 {0x9a0904, 0xffff0000},
1488 {0x9a096c, 0xe8},
1489 {0x9a0904, 0xffff},
1490 {0x9a096c, 0xe9},
1491 {0x9a0904, 0xffff0000},
1492 {0x9a096c, 0xea},
1493 {0x9a0904, 0xffff},
1494 {0x9a096c, 0xeb},
1495 {0x9a0904, 0xffff0000},
1496 {0x9a096c, 0xec},
1497 {0x9a0904, 0xffff},
1498 {0x9a096c, 0xed},
1499 {0x9a0904, 0xffff0000},
1500 {0x9a096c, 0xee},
1501 {0x9a0904, 0xff00ff},
1502 {0x9a096c, 0xef},
1503 {0x9a0904, 0xff00ff00},
1504 {0x9a096c, 0xf0},
1505 {0x9a0904, 0xff00ff},
1506 {0x9a096c, 0xf1},
1507 {0x9a0904, 0xff00ff00},
1508 {0x9a096c, 0xf2},
1509 {0x9a0904, 0xff00ff},
1510 {0x9a096c, 0xf3},
1511 {0x9a0904, 0xff00ff00},
1512 {0x9a096c, 0xf4},
1513 {0x9a0904, 0xff00ff},
1514 {0x9a096c, 0xf5},
1515 {0x9a0904, 0xff00ff00},
1516 {0x9a096c, 0xf6},
1517 {0x9a0904, 0xff00ff},
1518 {0x9a096c, 0xf7},
1519 {0x9a0904, 0xff00ff00},
1520 {0x9a096c, 0xf8},
1521 {0x9a0904, 0xff00ff},
1522 {0x9a096c, 0xf9},
1523 {0x9a0904, 0xff00ff00},
1524 {0x9a096c, 0xfa},
1525 {0x9a0904, 0xff00ff},
1526 {0x9a096c, 0xfb},
1527 {0x9a0904, 0xff00ff00},
1528 {0x9a096c, 0xfc},
1529 {0x9a0904, 0xff00ff},
1530 {0x9a096c, 0xfd},
1531 {0x9a0904, 0xff00ff00},
1532 {0x9a096c, 0xfe},
1533 {0x9a0904, 0x0},
1534 {0x9a096c, 0xff},
1535 {0x9a0904, 0xffffffff},
1536};
1537
1538/* MID SPEED TO LOW SPEED */
1539static u8 seq_script_step33_ls_gp106[] = {
1540 0x34, 0x00, 0x02, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x20, 0x00, 0x03, 0x00, 0x01,
1541 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x0D, 0x00, 0x00, 0x02,
1542 0x9A, 0x00, 0x00, 0x90, 0x8F, 0x02, 0x10, 0x09, 0x90, 0x00, 0x00, 0x00, 0x0C,
1543 0x00, 0x14, 0x09, 0x90, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x10, 0x49, 0x90, 0x00,
1544 0x00, 0x00, 0x0C, 0x00, 0x14, 0x49, 0x90, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x10,
1545 0x02, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x02, 0x00, 0xE8, 0x03,
1546 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x10, 0x03, 0x9A, 0x00, 0x01, 0x00, 0x00,
1547 0x00, 0x2E, 0x00, 0x02, 0x00, 0xE8, 0x03, 0x00, 0x00, 0x21, 0x00, 0x0D, 0x00,
1548 0x48, 0x03, 0x9A, 0x00, 0x88, 0x00, 0x70, 0x00, 0x00, 0x02, 0x9A, 0x00, 0x00,
1549 0x90, 0x8F, 0x82, 0x14, 0x03, 0x9A, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02,
1550 0x9A, 0x00, 0x00, 0x90, 0x8F, 0x02, 0x90, 0x00, 0x9A, 0x00, 0x61, 0x00, 0x00,
1551 0x00, 0x90, 0x00, 0x9A, 0x00, 0x7F, 0x00, 0x00, 0xC0, 0x2E, 0x00, 0x02, 0x00,
1552 0xE8, 0x03, 0x00, 0x00, 0x21, 0x00, 0x27, 0x00, 0x98, 0x06, 0x9A, 0x00, 0x00,
1553 0x00, 0x00, 0x00, 0x9C, 0x06, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x08,
1554 0x9A, 0x00, 0xE7, 0x8F, 0x83, 0x40, 0x38, 0x1F, 0x9A, 0x00, 0x00, 0x00, 0x01,
1555 0x00, 0x34, 0x1F, 0x9A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x34, 0x0D, 0x9A, 0x00,
1556 0x00, 0x00, 0x00, 0x00, 0x24, 0x08, 0x9A, 0x00, 0xE7, 0x8F, 0x8B, 0xC0, 0x24,
1557 0x08, 0x9A, 0x00, 0xE7, 0x8F, 0x83, 0x40, 0xF4, 0x73, 0x13, 0x00, 0x11, 0x00,
1558 0x01, 0x00, 0xF4, 0x73, 0x13, 0x00, 0x10, 0x00, 0x01, 0x00, 0xF4, 0x73, 0x13,
1559 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x20, 0x13, 0x00, 0x00, 0x00, 0x01, 0x18,
1560 0x00, 0x20, 0x13, 0x00, 0x02, 0x00, 0x01, 0x18, 0x20, 0x20, 0x13, 0x00, 0x00,
1561 0x00, 0x03, 0x20, 0x20, 0x73, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x20,
1562 0x13, 0x00, 0x01, 0x3B, 0x04, 0x00, 0x2C, 0x20, 0x13, 0x00, 0x00, 0x01, 0x00,
1563 0x00, 0x28, 0x20, 0x13, 0x00, 0x10, 0x00, 0x08, 0x10, 0x20, 0x20, 0x13, 0x00,
1564 0x01, 0x00, 0x03, 0x20, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01,
1565 0x00, 0x02, 0x00, 0x90, 0x73, 0x13, 0x00, 0x15, 0x00, 0x03, 0x00, 0x00, 0x00,
1566 0x02, 0x00, 0x00, 0xFA, 0x00, 0x00, 0x21, 0x00, 0x1F, 0x00, 0x2C, 0x20, 0x13,
1567 0x00, 0x00, 0x03, 0x00, 0x00, 0x28, 0x20, 0x13, 0x00, 0x10, 0x00, 0x04, 0x10,
1568 0xF4, 0x73, 0x13, 0x00, 0x00, 0x01, 0x01, 0x00, 0xF4, 0x73, 0x13, 0x00, 0x10,
1569 0x01, 0x01, 0x00, 0xEC, 0x73, 0x13, 0x00, 0x00, 0x00, 0x01, 0x00, 0xF4, 0x73,
1570 0x13, 0x00, 0x11, 0x01, 0x01, 0x00, 0xF4, 0x73, 0x13, 0x00, 0x11, 0x01, 0x00,
1571 0x00, 0x5C, 0x06, 0x9A, 0x00, 0x11, 0x00, 0x00, 0x00, 0x70, 0x06, 0x9A, 0x00,
1572 0x06, 0x13, 0x08, 0xB4, 0x98, 0x06, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9C,
1573 0x06, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x94, 0x06, 0x9A, 0x00, 0x0E, 0x06,
1574 0x0E, 0x06, 0xD4, 0x0E, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x40, 0xD4, 0x0E, 0x9A,
1575 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x08, 0x9A, 0x00, 0xE7, 0x8F, 0x80, 0x40,
1576 0x13, 0x00, 0x02, 0x00, 0x2C, 0x01, 0x00, 0x00, 0x2E, 0x00, 0x02, 0x00, 0x10,
1577 0x27, 0x00, 0x00, 0x21, 0x00, 0x1D, 0x00, 0x70, 0x06, 0x9A, 0x00, 0x06, 0x13,
1578 0x08, 0x34, 0x48, 0x02, 0x9A, 0x00, 0xA3, 0x44, 0x14, 0x86, 0x90, 0x02, 0x9A,
1579 0x00, 0x12, 0x2C, 0x18, 0x06, 0x94, 0x02, 0x9A, 0x00, 0x8A, 0x82, 0x41, 0x24,
1580 0x98, 0x02, 0x9A, 0x00, 0x11, 0x05, 0x06, 0x88, 0x9C, 0x02, 0x9A, 0x00, 0x8C,
1581 0x10, 0x00, 0x22, 0xA8, 0x02, 0x9A, 0x00, 0x0B, 0x86, 0x00, 0x01, 0x4C, 0x02,
1582 0x9A, 0x00, 0x85, 0x0C, 0x05, 0x06, 0x30, 0x1F, 0x9A, 0x00, 0x03, 0x16, 0x2C,
1583 0x00, 0xE0, 0x08, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x03, 0x9A, 0x00,
1584 0x00, 0x00, 0x00, 0x00, 0x94, 0x03, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1585 0x0B, 0x9A, 0x00, 0x06, 0x22, 0x22, 0x22, 0x90, 0x00, 0x9A, 0x00, 0x7E, 0x00,
1586 0x00, 0x40, 0x2E, 0x00, 0x02, 0x00, 0xD0, 0x07, 0x00, 0x00, 0x21, 0x00, 0x0D,
1587 0x00, 0x14, 0x03, 0x9A, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x03, 0x9A, 0x00,
1588 0x01, 0x00, 0x00, 0x00, 0x10, 0x02, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x80, 0x90,
1589 0x03, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x03, 0x9A, 0x00, 0x23, 0x01,
1590 0x30, 0x00, 0x00, 0x03, 0x9A, 0x00, 0x2D, 0x02, 0x00, 0x00, 0x2E, 0x00, 0x02,
1591 0x00, 0xE8, 0x03, 0x00, 0x00, 0x21, 0x00, 0x07, 0x00, 0x00, 0x02, 0x9A, 0x00,
1592 0x00, 0x90, 0x8F, 0x82, 0x18, 0x03, 0x9A, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
1593 0x02, 0x9A, 0x00, 0x00, 0x90, 0x8F, 0x02, 0x2E, 0x00, 0x02, 0x00, 0xE8, 0x03,
1594 0x00, 0x00, 0x21, 0x00, 0x0D, 0x00, 0x78, 0x09, 0x9A, 0x00, 0x0B, 0x1E, 0x7A,
1595 0x88, 0x30, 0x08, 0x9A, 0x00, 0x91, 0x10, 0x27, 0x00, 0x10, 0x09, 0x90, 0x00,
1596 0x00, 0x00, 0x0A, 0x98, 0x14, 0x09, 0x90, 0x00, 0x00, 0x00, 0x0A, 0x98, 0x10,
1597 0x49, 0x90, 0x00, 0x00, 0x00, 0x0A, 0x98, 0x14, 0x49, 0x90, 0x00, 0x00, 0x00,
1598 0x0A, 0x98, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02,
1599 0x00, 0x74, 0x09, 0x90, 0x00, 0x15, 0x00, 0x03, 0x00, 0x0F, 0x00, 0x00, 0x00,
1600 0x20, 0xA1, 0x07, 0x00, 0x01, 0x00, 0x02, 0x00, 0x74, 0x49, 0x90, 0x00, 0x15,
1601 0x00, 0x03, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x20, 0xA1, 0x07, 0x00, 0x21, 0x00,
1602 0x0D, 0x00, 0x30, 0x08, 0x9A, 0x00, 0x91, 0x10, 0x27, 0x01, 0x30, 0x08, 0x9A,
1603 0x00, 0x91, 0x10, 0x27, 0x00, 0x10, 0x09, 0x90, 0x00, 0x00, 0x00, 0x08, 0x19,
1604 0x14, 0x09, 0x90, 0x00, 0x00, 0x00, 0x08, 0x19, 0x10, 0x49, 0x90, 0x00, 0x00,
1605 0x00, 0x08, 0x19, 0x14, 0x49, 0x90, 0x00, 0x00, 0x00, 0x08, 0x19, 0x20, 0x00,
1606 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x02,
1607 0x00, 0x0B, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x00, 0x02, 0x9A, 0x00,
1608 0x00, 0x98, 0x8F, 0x02, 0x16, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
1609};
1610
1611/* LOW SPEED TO MID SPEED */
1612static u8 seq_script_step33_gp106[] = {
1613 0x34, 0x00, 0x02, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x20, 0x00, 0x03, 0x00, 0x01,
1614 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x0D, 0x00, 0x00, 0x02,
1615 0x9A, 0x00, 0x00, 0x90, 0x8F, 0x02, 0x10, 0x09, 0x90, 0x00, 0x00, 0x00, 0x0C,
1616 0x00, 0x14, 0x09, 0x90, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x10, 0x49, 0x90, 0x00,
1617 0x00, 0x00, 0x0C, 0x00, 0x14, 0x49, 0x90, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x10,
1618 0x02, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x02, 0x00, 0xE8, 0x03,
1619 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x10, 0x03, 0x9A, 0x00, 0x01, 0x00, 0x00,
1620 0x00, 0x2E, 0x00, 0x02, 0x00, 0xE8, 0x03, 0x00, 0x00, 0x21, 0x00, 0x0D, 0x00,
1621 0x48, 0x03, 0x9A, 0x00, 0x88, 0x00, 0x70, 0x00, 0x00, 0x02, 0x9A, 0x00, 0x00,
1622 0x90, 0x8F, 0x82, 0x14, 0x03, 0x9A, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02,
1623 0x9A, 0x00, 0x00, 0x90, 0x8F, 0x02, 0x90, 0x00, 0x9A, 0x00, 0x61, 0x00, 0x00,
1624 0x00, 0x90, 0x00, 0x9A, 0x00, 0x7F, 0x00, 0x00, 0xC0, 0x2E, 0x00, 0x02, 0x00,
1625 0xE8, 0x03, 0x00, 0x00, 0x21, 0x00, 0x27, 0x00, 0x98, 0x06, 0x9A, 0x00, 0x00,
1626 0x00, 0x00, 0x00, 0x9C, 0x06, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x08,
1627 0x9A, 0x00, 0xE7, 0x8F, 0x83, 0x40, 0x38, 0x1F, 0x9A, 0x00, 0x00, 0x00, 0x01,
1628 0x00, 0x34, 0x1F, 0x9A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x34, 0x0D, 0x9A, 0x00,
1629 0x00, 0x00, 0x00, 0x00, 0x24, 0x08, 0x9A, 0x00, 0xE7, 0x8F, 0x8B, 0xC0, 0x24,
1630 0x08, 0x9A, 0x00, 0xE7, 0x8F, 0x83, 0x40, 0xF4, 0x73, 0x13, 0x00, 0x11, 0x00,
1631 0x01, 0x00, 0xF4, 0x73, 0x13, 0x00, 0x10, 0x00, 0x01, 0x00, 0xF4, 0x73, 0x13,
1632 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x20, 0x13, 0x00, 0x00, 0x00, 0x01, 0x18,
1633 0x00, 0x20, 0x13, 0x00, 0x02, 0x00, 0x01, 0x18, 0x20, 0x20, 0x13, 0x00, 0x00,
1634 0x00, 0x03, 0x20, 0x20, 0x73, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x20,
1635 0x13, 0x00, 0x01, 0x3B, 0x02, 0x00, 0x2C, 0x20, 0x13, 0x00, 0x00, 0x01, 0x00,
1636 0x00, 0x28, 0x20, 0x13, 0x00, 0x10, 0x00, 0x08, 0x10, 0x20, 0x20, 0x13, 0x00,
1637 0x01, 0x00, 0x03, 0x20, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01,
1638 0x00, 0x02, 0x00, 0x90, 0x73, 0x13, 0x00, 0x15, 0x00, 0x03, 0x00, 0x00, 0x00,
1639 0x02, 0x00, 0x00, 0xFA, 0x00, 0x00, 0x21, 0x00, 0x1F, 0x00, 0x2C, 0x20, 0x13,
1640 0x00, 0x00, 0x03, 0x00, 0x00, 0x28, 0x20, 0x13, 0x00, 0x10, 0x00, 0x04, 0x10,
1641 0xF4, 0x73, 0x13, 0x00, 0x00, 0x01, 0x01, 0x00, 0xF4, 0x73, 0x13, 0x00, 0x10,
1642 0x01, 0x01, 0x00, 0xEC, 0x73, 0x13, 0x00, 0x00, 0x00, 0x01, 0x00, 0xF4, 0x73,
1643 0x13, 0x00, 0x11, 0x01, 0x01, 0x00, 0xF4, 0x73, 0x13, 0x00, 0x11, 0x01, 0x00,
1644 0x00, 0x5C, 0x06, 0x9A, 0x00, 0x11, 0x00, 0x00, 0x00, 0x70, 0x06, 0x9A, 0x00,
1645 0x06, 0x13, 0x08, 0xB4, 0x98, 0x06, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9C,
1646 0x06, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x94, 0x06, 0x9A, 0x00, 0x0E, 0x06,
1647 0x0E, 0x06, 0xD4, 0x0E, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x40, 0xD4, 0x0E, 0x9A,
1648 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x08, 0x9A, 0x00, 0xE7, 0x8F, 0x80, 0x40,
1649 0x13, 0x00, 0x02, 0x00, 0x2C, 0x01, 0x00, 0x00, 0x2E, 0x00, 0x02, 0x00, 0x10,
1650 0x27, 0x00, 0x00, 0x21, 0x00, 0x1D, 0x00, 0x70, 0x06, 0x9A, 0x00, 0x06, 0x13,
1651 0x08, 0x34, 0x48, 0x02, 0x9A, 0x00, 0xA3, 0x44, 0x14, 0x86, 0x90, 0x02, 0x9A,
1652 0x00, 0x12, 0x2C, 0x18, 0x06, 0x94, 0x02, 0x9A, 0x00, 0x8A, 0x82, 0x41, 0x24,
1653 0x98, 0x02, 0x9A, 0x00, 0x11, 0x05, 0x06, 0x88, 0x9C, 0x02, 0x9A, 0x00, 0x8C,
1654 0x10, 0x00, 0x22, 0xA8, 0x02, 0x9A, 0x00, 0x0B, 0x86, 0x00, 0x01, 0x4C, 0x02,
1655 0x9A, 0x00, 0x85, 0x0C, 0x05, 0x06, 0x30, 0x1F, 0x9A, 0x00, 0x03, 0x16, 0x2C,
1656 0x00, 0xE0, 0x08, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x03, 0x9A, 0x00,
1657 0x00, 0x00, 0x00, 0x00, 0x94, 0x03, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1658 0x0B, 0x9A, 0x00, 0x06, 0x22, 0x22, 0x22, 0x90, 0x00, 0x9A, 0x00, 0x7E, 0x00,
1659 0x00, 0x40, 0x2E, 0x00, 0x02, 0x00, 0xD0, 0x07, 0x00, 0x00, 0x21, 0x00, 0x0D,
1660 0x00, 0x14, 0x03, 0x9A, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x03, 0x9A, 0x00,
1661 0x01, 0x00, 0x00, 0x00, 0x10, 0x02, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x80, 0x90,
1662 0x03, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x03, 0x9A, 0x00, 0x23, 0x01,
1663 0x30, 0x00, 0x00, 0x03, 0x9A, 0x00, 0x2D, 0x02, 0x00, 0x00, 0x2E, 0x00, 0x02,
1664 0x00, 0xE8, 0x03, 0x00, 0x00, 0x21, 0x00, 0x07, 0x00, 0x00, 0x02, 0x9A, 0x00,
1665 0x00, 0x90, 0x8F, 0x82, 0x18, 0x03, 0x9A, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
1666 0x02, 0x9A, 0x00, 0x00, 0x90, 0x8F, 0x02, 0x2E, 0x00, 0x02, 0x00, 0xE8, 0x03,
1667 0x00, 0x00, 0x21, 0x00, 0x0D, 0x00, 0x78, 0x09, 0x9A, 0x00, 0x0B, 0x1E, 0x7A,
1668 0x88, 0x30, 0x08, 0x9A, 0x00, 0x91, 0x10, 0x27, 0x00, 0x10, 0x09, 0x90, 0x00,
1669 0x00, 0x00, 0x0A, 0x98, 0x14, 0x09, 0x90, 0x00, 0x00, 0x00, 0x0A, 0x98, 0x10,
1670 0x49, 0x90, 0x00, 0x00, 0x00, 0x0A, 0x98, 0x14, 0x49, 0x90, 0x00, 0x00, 0x00,
1671 0x0A, 0x98, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02,
1672 0x00, 0x74, 0x09, 0x90, 0x00, 0x15, 0x00, 0x03, 0x00, 0x0F, 0x00, 0x00, 0x00,
1673 0x20, 0xA1, 0x07, 0x00, 0x01, 0x00, 0x02, 0x00, 0x74, 0x49, 0x90, 0x00, 0x15,
1674 0x00, 0x03, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x20, 0xA1, 0x07, 0x00, 0x21, 0x00,
1675 0x0D, 0x00, 0x30, 0x08, 0x9A, 0x00, 0x91, 0x10, 0x27, 0x01, 0x30, 0x08, 0x9A,
1676 0x00, 0x91, 0x10, 0x27, 0x00, 0x10, 0x09, 0x90, 0x00, 0x00, 0x00, 0x08, 0x19,
1677 0x14, 0x09, 0x90, 0x00, 0x00, 0x00, 0x08, 0x19, 0x10, 0x49, 0x90, 0x00, 0x00,
1678 0x00, 0x08, 0x19, 0x14, 0x49, 0x90, 0x00, 0x00, 0x00, 0x08, 0x19, 0x20, 0x00,
1679 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x02,
1680 0x00, 0x0B, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x00, 0x02, 0x9A, 0x00,
1681 0x00, 0x98, 0x8F, 0x02, 0x16, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
1682};
1683
1684/* LOW/MID SPEED TO HIGH SPEED */
1685static u8 seq_script_step28_gp106[] = {
1686 0x34, 0x00, 0x02, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x20, 0x00, 0x03, 0x00, 0x01,
1687 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x07, 0x00, 0x30, 0x03,
1688 0x9A, 0x00, 0x14, 0x00, 0x10, 0x00, 0x38, 0xD6, 0x00, 0x00, 0x00, 0x60, 0x00,
1689 0x00, 0x04, 0xD6, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x02, 0x00,
1690 0x20, 0x4E, 0x00, 0x00, 0x21, 0x00, 0x0D, 0x00, 0x00, 0x02, 0x9A, 0x00, 0x00,
1691 0x90, 0x8F, 0x02, 0x10, 0x09, 0x90, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x14, 0x09,
1692 0x90, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x10, 0x49, 0x90, 0x00, 0x00, 0x00, 0x0C,
1693 0x00, 0x14, 0x49, 0x90, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x10, 0x02, 0x9A, 0x00,
1694 0x00, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x02, 0x00, 0xE8, 0x03, 0x00, 0x00, 0x21,
1695 0x00, 0x03, 0x00, 0x10, 0x03, 0x9A, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2E, 0x00,
1696 0x02, 0x00, 0xE8, 0x03, 0x00, 0x00, 0x21, 0x00, 0x0D, 0x00, 0x48, 0x03, 0x9A,
1697 0x00, 0x88, 0x00, 0x70, 0x00, 0x00, 0x02, 0x9A, 0x00, 0x00, 0x90, 0x8F, 0x82,
1698 0x14, 0x03, 0x9A, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x9A, 0x00, 0x00,
1699 0x90, 0x8F, 0x02, 0x90, 0x00, 0x9A, 0x00, 0x61, 0x00, 0x00, 0x00, 0x90, 0x00,
1700 0x9A, 0x00, 0x7F, 0x00, 0x00, 0xC0, 0x2E, 0x00, 0x02, 0x00, 0xE8, 0x03, 0x00,
1701 0x00, 0x21, 0x00, 0x27, 0x00, 0x98, 0x06, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x00,
1702 0x9C, 0x06, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x08, 0x9A, 0x00, 0xE7,
1703 0x8F, 0x88, 0xF7, 0x40, 0x0D, 0x9A, 0x00, 0x20, 0xE0, 0x01, 0x00, 0x00, 0x02,
1704 0x9A, 0x00, 0x00, 0x90, 0x8F, 0x1A, 0x00, 0x08, 0x9A, 0x00, 0x00, 0x00, 0x00,
1705 0x00, 0xF0, 0x73, 0x13, 0x00, 0x03, 0x00, 0x00, 0x00, 0x30, 0x08, 0x9A, 0x00,
1706 0x90, 0x90, 0x67, 0x00, 0xF4, 0x73, 0x13, 0x00, 0x11, 0x00, 0x01, 0x00, 0xF4,
1707 0x73, 0x13, 0x00, 0x10, 0x00, 0x01, 0x00, 0xF4, 0x73, 0x13, 0x00, 0x00, 0x00,
1708 0x01, 0x00, 0x20, 0x20, 0x13, 0x00, 0x00, 0x00, 0x03, 0x20, 0x20, 0x73, 0x13,
1709 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x20, 0x13, 0x00, 0x04, 0x00, 0x00, 0x00,
1710 0x34, 0x20, 0x13, 0x00, 0x00, 0x00, 0x8A, 0xF9, 0x24, 0x20, 0x13, 0x00, 0x01,
1711 0x32, 0x05, 0x00, 0x2C, 0x20, 0x13, 0x00, 0x00, 0x01, 0x00, 0x00, 0x28, 0x20,
1712 0x13, 0x00, 0x10, 0x00, 0x08, 0x10, 0x20, 0x20, 0x13, 0x00, 0x01, 0x00, 0x03,
1713 0x20, 0x34, 0x00, 0x02, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
1714 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x90, 0x73, 0x13, 0x00, 0x15,
1715 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0xFA, 0x00, 0x00, 0x34, 0x00,
1716 0x02, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x21, 0x00, 0x0D, 0x00, 0x2C, 0x20, 0x13,
1717 0x00, 0x00, 0x03, 0x00, 0x00, 0x28, 0x20, 0x13, 0x00, 0x10, 0x00, 0x04, 0x10,
1718 0xF4, 0x73, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x13, 0x00, 0x00,
1719 0x00, 0x01, 0x98, 0x04, 0x20, 0x13, 0x00, 0x01, 0x0B, 0x01, 0x00, 0x00, 0x20,
1720 0x13, 0x00, 0x01, 0x00, 0x01, 0x98, 0x34, 0x00, 0x02, 0x00, 0x0D, 0x00, 0x00,
1721 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00,
1722 0x90, 0x73, 0x13, 0x00, 0x15, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
1723 0xFA, 0x00, 0x00, 0x34, 0x00, 0x02, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x21, 0x00,
1724 0x1D, 0x00, 0xF4, 0x73, 0x13, 0x00, 0x00, 0x11, 0x00, 0x00, 0xF4, 0x73, 0x13,
1725 0x00, 0x10, 0x11, 0x00, 0x00, 0xEC, 0x73, 0x13, 0x00, 0x00, 0x00, 0x03, 0x00,
1726 0xF0, 0x73, 0x13, 0x00, 0x02, 0x00, 0x00, 0x00, 0xF4, 0x73, 0x13, 0x00, 0x12,
1727 0x11, 0x00, 0x00, 0xF4, 0x73, 0x13, 0x00, 0x12, 0x00, 0x00, 0x00, 0x08, 0x08,
1728 0x9A, 0x00, 0x70, 0x00, 0x08, 0x48, 0x00, 0x02, 0x9A, 0x00, 0x00, 0x10, 0x8F,
1729 0x1A, 0x24, 0x08, 0x9A, 0x00, 0xE5, 0x8F, 0x88, 0xF7, 0x08, 0x08, 0x9A, 0x00,
1730 0x70, 0x00, 0xA8, 0x4A, 0x24, 0x08, 0x9A, 0x00, 0x85, 0x8F, 0x88, 0xF7, 0x38,
1731 0x1F, 0x9A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x34, 0x1F, 0x9A, 0x00, 0x00, 0x00,
1732 0x01, 0x00, 0x34, 0x0D, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02,
1733 0x00, 0x2C, 0x01, 0x00, 0x00, 0x21, 0x00, 0x09, 0x00, 0x5C, 0x06, 0x9A, 0x00,
1734 0x22, 0x00, 0x00, 0x00, 0x0C, 0x06, 0x9A, 0x00, 0xD0, 0x20, 0x00, 0xFD, 0xD4,
1735 0x0E, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x40, 0xD4, 0x0E, 0x9A, 0x00, 0x00, 0x00,
1736 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x2C, 0x01, 0x00, 0x00, 0x21, 0x00, 0x25,
1737 0x00, 0x2C, 0x08, 0x9A, 0x00, 0x00, 0x00, 0x05, 0x00, 0x30, 0x08, 0x9A, 0x00,
1738 0x90, 0xA0, 0x67, 0x00, 0x48, 0x02, 0x9A, 0x00, 0xA3, 0x44, 0x20, 0x95, 0x90,
1739 0x02, 0x9A, 0x00, 0x46, 0xAE, 0x60, 0x16, 0x94, 0x02, 0x9A, 0x00, 0x96, 0x02,
1740 0xF6, 0x28, 0x98, 0x02, 0x9A, 0x00, 0x00, 0x09, 0x16, 0x88, 0x9C, 0x02, 0x9A,
1741 0x00, 0x4C, 0x39, 0x00, 0x24, 0xA0, 0x02, 0x9A, 0x00, 0x32, 0x80, 0x83, 0xD5,
1742 0xA8, 0x02, 0x9A, 0x00, 0x0F, 0x86, 0x00, 0x02, 0x14, 0x06, 0x9A, 0x00, 0x77,
1743 0x4E, 0x04, 0x40, 0x10, 0x06, 0x9A, 0x00, 0x77, 0x4E, 0x04, 0x40, 0x78, 0x07,
1744 0x10, 0x00, 0x44, 0x04, 0x00, 0x82, 0x4C, 0x02, 0x9A, 0x00, 0x85, 0x0C, 0x05,
1745 0x15, 0xE0, 0x08, 0x9A, 0x00, 0x11, 0x00, 0x00, 0x00, 0x90, 0x03, 0x9A, 0x00,
1746 0x00, 0x00, 0x00, 0x00, 0x94, 0x03, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1747 0x0B, 0x9A, 0x00, 0x06, 0x22, 0x22, 0x22, 0x90, 0x00, 0x9A, 0x00, 0x7E, 0x00,
1748 0x00, 0x40, 0x2E, 0x00, 0x02, 0x00, 0xD0, 0x07, 0x00, 0x00, 0x21, 0x00, 0x13,
1749 0x00, 0x14, 0x03, 0x9A, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x03, 0x9A, 0x00,
1750 0x01, 0x00, 0x00, 0x00, 0x10, 0x02, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x80, 0x90,
1751 0x03, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x94, 0x02, 0x9A, 0x00, 0x96, 0x02,
1752 0xF6, 0x24, 0x10, 0x09, 0x90, 0x00, 0x00, 0x00, 0x01, 0xA4, 0x14, 0x09, 0x90,
1753 0x00, 0x00, 0x00, 0x01, 0xA4, 0x10, 0x49, 0x90, 0x00, 0x00, 0x00, 0x01, 0xA4,
1754 0x14, 0x49, 0x90, 0x00, 0x00, 0x00, 0x01, 0xA4, 0x34, 0x00, 0x02, 0x00, 0x0F,
1755 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
1756 0x02, 0x00, 0x74, 0x09, 0x90, 0x00, 0x15, 0x00, 0x03, 0x00, 0x0F, 0x00, 0x00,
1757 0x00, 0x20, 0xA1, 0x07, 0x00, 0x01, 0x00, 0x02, 0x00, 0x74, 0x49, 0x90, 0x00,
1758 0x15, 0x00, 0x03, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x20, 0xA1, 0x07, 0x00, 0x34,
1759 0x00, 0x02, 0x00, 0x10, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x02, 0x00, 0xE8, 0x03,
1760 0x00, 0x00, 0x21, 0x00, 0x0B, 0x00, 0x94, 0x02, 0x9A, 0x00, 0x96, 0x02, 0xF6,
1761 0x28, 0x38, 0x03, 0x9A, 0x00, 0x03, 0x01, 0x30, 0x00, 0x3C, 0x03, 0x9A, 0x00,
1762 0xFF, 0x01, 0x40, 0x00, 0x00, 0x03, 0x9A, 0x00, 0x0D, 0x02, 0x00, 0x00, 0x54,
1763 0x03, 0x9A, 0x00, 0x03, 0x00, 0x80, 0x00, 0x2E, 0x00, 0x02, 0x00, 0xE8, 0x03,
1764 0x00, 0x00, 0x21, 0x00, 0x09, 0x00, 0x48, 0x03, 0x9A, 0x00, 0x00, 0x00, 0x70,
1765 0x00, 0x00, 0x02, 0x9A, 0x00, 0x00, 0x10, 0x8F, 0x9A, 0x18, 0x03, 0x9A, 0x00,
1766 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x9A, 0x00, 0x00, 0x10, 0x8F, 0x1A, 0x2E,
1767 0x00, 0x02, 0x00, 0xE8, 0x03, 0x00, 0x00, 0x21, 0x00, 0x0B, 0x00, 0x78, 0x09,
1768 0x9A, 0x00, 0x0F, 0x1E, 0x7E, 0x88, 0x10, 0x09, 0x90, 0x00, 0x00, 0x00, 0x0E,
1769 0xA4, 0x14, 0x09, 0x90, 0x00, 0x00, 0x00, 0x0E, 0xA4, 0x10, 0x49, 0x90, 0x00,
1770 0x00, 0x00, 0x0E, 0xA4, 0x14, 0x49, 0x90, 0x00, 0x00, 0x00, 0x0E, 0xA4, 0x34,
1771 0x00, 0x02, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
1772 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x74, 0x09, 0x90, 0x00, 0x15, 0x00, 0x03,
1773 0x00, 0x0F, 0x00, 0x00, 0x00, 0x20, 0xA1, 0x07, 0x00, 0x01, 0x00, 0x02, 0x00,
1774 0x74, 0x49, 0x90, 0x00, 0x15, 0x00, 0x03, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x20,
1775 0xA1, 0x07, 0x00, 0x34, 0x00, 0x02, 0x00, 0x12, 0x00, 0x00, 0x00, 0x2E, 0x00,
1776 0x02, 0x00, 0xE8, 0x03, 0x00, 0x00, 0x21, 0x00, 0x0B, 0x00, 0x00, 0x02, 0x9A,
1777 0x00, 0x00, 0x10, 0x8F, 0x3A, 0x10, 0x09, 0x90, 0x00, 0x00, 0x00, 0x0C, 0x25,
1778 0x14, 0x09, 0x90, 0x00, 0x00, 0x00, 0x0C, 0x25, 0x10, 0x49, 0x90, 0x00, 0x00,
1779 0x00, 0x0C, 0x25, 0x14, 0x49, 0x90, 0x00, 0x00, 0x00, 0x0C, 0x25, 0x20, 0x00,
1780 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x02,
1781 0x00, 0x13, 0x00, 0x00, 0x00, 0x16, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00
1782};
1783
1784/* HIGH SPEED TO LOW SPEED */
1785static u8 seq_script_step32_ls_gp106[] = {
1786 0x34, 0x00, 0x02, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x20, 0x00, 0x03, 0x00, 0x01,
1787 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x0B, 0x00, 0x10, 0x09,
1788 0x90, 0x00, 0x00, 0x00, 0x0C, 0x24, 0x14, 0x09, 0x90, 0x00, 0x00, 0x00, 0x0C,
1789 0x24, 0x10, 0x49, 0x90, 0x00, 0x00, 0x00, 0x0C, 0x24, 0x14, 0x49, 0x90, 0x00,
1790 0x00, 0x00, 0x0C, 0x24, 0x10, 0x02, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2E,
1791 0x00, 0x02, 0x00, 0xE8, 0x03, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x10, 0x03,
1792 0x9A, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x02, 0x00, 0xE8, 0x03, 0x00,
1793 0x00, 0x21, 0x00, 0x0D, 0x00, 0x48, 0x03, 0x9A, 0x00, 0x00, 0x00, 0x70, 0x00,
1794 0x00, 0x02, 0x9A, 0x00, 0x00, 0x10, 0x8F, 0x82, 0x14, 0x03, 0x9A, 0x00, 0x01,
1795 0x00, 0x00, 0x00, 0x00, 0x02, 0x9A, 0x00, 0x00, 0x10, 0x8F, 0x02, 0x90, 0x00,
1796 0x9A, 0x00, 0x61, 0x00, 0x00, 0x00, 0x90, 0x00, 0x9A, 0x00, 0x7F, 0x00, 0x00,
1797 0xC0, 0x2E, 0x00, 0x02, 0x00, 0xE8, 0x03, 0x00, 0x00, 0x21, 0x00, 0x35, 0x00,
1798 0x98, 0x06, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9C, 0x06, 0x9A, 0x00, 0x00,
1799 0x00, 0x00, 0x00, 0x24, 0x08, 0x9A, 0x00, 0x85, 0x8F, 0x8B, 0xF7, 0x38, 0x1F,
1800 0x9A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x34, 0x1F, 0x9A, 0x00, 0x00, 0x00, 0x01,
1801 0x00, 0x34, 0x0D, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x08, 0x9A, 0x00,
1802 0xE7, 0x8F, 0x8B, 0xF7, 0x40, 0x0D, 0x9A, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x24,
1803 0x08, 0x9A, 0x00, 0xE7, 0x8F, 0x83, 0x40, 0x08, 0x08, 0x9A, 0x00, 0x70, 0x00,
1804 0xA0, 0x4A, 0x00, 0x02, 0x9A, 0x00, 0x00, 0x90, 0x8F, 0x02, 0x30, 0x08, 0x9A,
1805 0x00, 0x90, 0x20, 0x67, 0x01, 0x30, 0x08, 0x9A, 0x00, 0x90, 0x20, 0x67, 0x00,
1806 0xF4, 0x73, 0x13, 0x00, 0x12, 0x11, 0x00, 0x00, 0xF4, 0x73, 0x13, 0x00, 0x10,
1807 0x11, 0x00, 0x00, 0xF4, 0x73, 0x13, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x20,
1808 0x13, 0x00, 0x00, 0x00, 0x03, 0x98, 0x00, 0x20, 0x13, 0x00, 0x02, 0x00, 0x03,
1809 0x98, 0x20, 0x20, 0x13, 0x00, 0x00, 0x00, 0x03, 0x20, 0x20, 0x73, 0x13, 0x00,
1810 0x00, 0x00, 0x00, 0x00, 0x30, 0x20, 0x13, 0x00, 0x06, 0x00, 0x00, 0x10, 0x34,
1811 0x20, 0x13, 0x00, 0x00, 0x10, 0x67, 0x06, 0x24, 0x20, 0x13, 0x00, 0x01, 0x3B,
1812 0x04, 0x00, 0x2C, 0x20, 0x13, 0x00, 0x00, 0x01, 0x00, 0x00, 0x28, 0x20, 0x13,
1813 0x00, 0x10, 0x00, 0x08, 0x10, 0x20, 0x20, 0x13, 0x00, 0x01, 0x00, 0x03, 0x20,
1814 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x90,
1815 0x73, 0x13, 0x00, 0x15, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0xFA,
1816 0x00, 0x00, 0x21, 0x00, 0x23, 0x00, 0x2C, 0x20, 0x13, 0x00, 0x00, 0x03, 0x00,
1817 0x00, 0x28, 0x20, 0x13, 0x00, 0x10, 0x00, 0x04, 0x10, 0xF4, 0x73, 0x13, 0x00,
1818 0x00, 0x11, 0x01, 0x00, 0xF4, 0x73, 0x13, 0x00, 0x10, 0x11, 0x01, 0x00, 0xF0,
1819 0x73, 0x13, 0x00, 0x01, 0x00, 0x00, 0x00, 0xEC, 0x73, 0x13, 0x00, 0x00, 0x00,
1820 0x01, 0x00, 0xF4, 0x73, 0x13, 0x00, 0x11, 0x11, 0x01, 0x00, 0xF4, 0x73, 0x13,
1821 0x00, 0x11, 0x11, 0x00, 0x00, 0x30, 0x08, 0x9A, 0x00, 0x91, 0x20, 0x27, 0x00,
1822 0x5C, 0x06, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x06, 0x9A, 0x00, 0x06,
1823 0x06, 0x06, 0x06, 0x9C, 0x06, 0x9A, 0x00, 0x06, 0x06, 0x06, 0x06, 0x94, 0x06,
1824 0x9A, 0x00, 0x0E, 0x06, 0x0E, 0x06, 0x0C, 0x06, 0x9A, 0x00, 0x50, 0x20, 0x00,
1825 0xFD, 0xD4, 0x0E, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x40, 0xD4, 0x0E, 0x9A, 0x00,
1826 0x00, 0x00, 0x00, 0x00, 0x24, 0x08, 0x9A, 0x00, 0xE7, 0x8F, 0x80, 0x40, 0x13,
1827 0x00, 0x02, 0x00, 0x2C, 0x01, 0x00, 0x00, 0x21, 0x00, 0x23, 0x00, 0x2C, 0x08,
1828 0x9A, 0x00, 0x00, 0x00, 0x15, 0x00, 0x30, 0x08, 0x9A, 0x00, 0x91, 0x10, 0x27,
1829 0x00, 0x48, 0x02, 0x9A, 0x00, 0xA3, 0x44, 0x14, 0x84, 0x90, 0x02, 0x9A, 0x00,
1830 0x0A, 0x17, 0x0E, 0x03, 0x94, 0x02, 0x9A, 0x00, 0x89, 0x02, 0x21, 0x24, 0x98,
1831 0x02, 0x9A, 0x00, 0x11, 0x04, 0x05, 0x88, 0x9C, 0x02, 0x9A, 0x00, 0x6C, 0x10,
1832 0x00, 0x22, 0xA0, 0x02, 0x9A, 0x00, 0x32, 0x00, 0x61, 0xD3, 0xA8, 0x02, 0x9A,
1833 0x00, 0x0B, 0x86, 0x00, 0x02, 0x14, 0x06, 0x9A, 0x00, 0x77, 0x3E, 0x03, 0x30,
1834 0x10, 0x06, 0x9A, 0x00, 0x77, 0x3E, 0x03, 0x30, 0x08, 0x08, 0x9A, 0x00, 0x70,
1835 0x00, 0x00, 0x48, 0x78, 0x07, 0x10, 0x00, 0x33, 0x03, 0x00, 0x82, 0x4C, 0x02,
1836 0x9A, 0x00, 0x85, 0x0C, 0x05, 0x04, 0x30, 0x1F, 0x9A, 0x00, 0x03, 0x16, 0x2C,
1837 0x00, 0xE0, 0x08, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0x9A, 0x00,
1838 0x7E, 0x00, 0x00, 0x40, 0x2E, 0x00, 0x02, 0x00, 0xD0, 0x07, 0x00, 0x00, 0x21,
1839 0x00, 0x0D, 0x00, 0x14, 0x03, 0x9A, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x03,
1840 0x9A, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x02, 0x9A, 0x00, 0x00, 0x00, 0x00,
1841 0x80, 0x38, 0x03, 0x9A, 0x00, 0x23, 0x00, 0x30, 0x00, 0x00, 0x03, 0x9A, 0x00,
1842 0x25, 0x01, 0x00, 0x00, 0x54, 0x03, 0x9A, 0x00, 0x00, 0x00, 0x80, 0x00, 0x2E,
1843 0x00, 0x02, 0x00, 0xE8, 0x03, 0x00, 0x00, 0x21, 0x00, 0x09, 0x00, 0x30, 0x03,
1844 0x9A, 0x00, 0x30, 0x00, 0x10, 0x00, 0x48, 0x03, 0x9A, 0x00, 0x88, 0x00, 0x70,
1845 0x00, 0x38, 0xD6, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x04, 0xD6, 0x00, 0x00,
1846 0x01, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x02, 0x00, 0x20, 0x4E, 0x00, 0x00, 0x21,
1847 0x00, 0x07, 0x00, 0x00, 0x02, 0x9A, 0x00, 0x00, 0x90, 0x8F, 0x82, 0x18, 0x03,
1848 0x9A, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x9A, 0x00, 0x00, 0x90, 0x8F,
1849 0x02, 0x2E, 0x00, 0x02, 0x00, 0xE8, 0x03, 0x00, 0x00, 0x21, 0x00, 0x0D, 0x00,
1850 0x78, 0x09, 0x9A, 0x00, 0x0F, 0x3E, 0x7A, 0x88, 0x30, 0x08, 0x9A, 0x00, 0x91,
1851 0x10, 0x27, 0x00, 0x10, 0x09, 0x90, 0x00, 0x00, 0x00, 0x0A, 0x88, 0x14, 0x09,
1852 0x90, 0x00, 0x00, 0x00, 0x0A, 0x88, 0x10, 0x49, 0x90, 0x00, 0x00, 0x00, 0x0A,
1853 0x88, 0x14, 0x49, 0x90, 0x00, 0x00, 0x00, 0x0A, 0x88, 0x00, 0x00, 0x02, 0x00,
1854 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x74, 0x09, 0x90, 0x00, 0x15,
1855 0x00, 0x03, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x20, 0xA1, 0x07, 0x00, 0x01, 0x00,
1856 0x02, 0x00, 0x74, 0x49, 0x90, 0x00, 0x15, 0x00, 0x03, 0x00, 0x0F, 0x00, 0x00,
1857 0x00, 0x20, 0xA1, 0x07, 0x00, 0x21, 0x00, 0x05, 0x00, 0x30, 0x08, 0x9A, 0x00,
1858 0x91, 0x10, 0x27, 0x01, 0x30, 0x08, 0x9A, 0x00, 0x91, 0x10, 0x27, 0x00, 0x20,
1859 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00,
1860 0x02, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x00, 0x02, 0x9A,
1861 0x00, 0x00, 0x98, 0x8F, 0x02, 0x16, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
1862};
1863
1864/* HIGH SPEED TO LOW/MID SPEED */
1865static u8 seq_script_step32_gp106[] = {
1866 0x34, 0x00, 0x02, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x20, 0x00, 0x03, 0x00, 0x01,
1867 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x0B, 0x00, 0x10, 0x09,
1868 0x90, 0x00, 0x00, 0x00, 0x0C, 0x24, 0x14, 0x09, 0x90, 0x00, 0x00, 0x00, 0x0C,
1869 0x24, 0x10, 0x49, 0x90, 0x00, 0x00, 0x00, 0x0C, 0x24, 0x14, 0x49, 0x90, 0x00,
1870 0x00, 0x00, 0x0C, 0x24, 0x10, 0x02, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2E,
1871 0x00, 0x02, 0x00, 0xE8, 0x03, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x10, 0x03,
1872 0x9A, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x02, 0x00, 0xE8, 0x03, 0x00,
1873 0x00, 0x21, 0x00, 0x0D, 0x00, 0x48, 0x03, 0x9A, 0x00, 0x00, 0x00, 0x70, 0x00,
1874 0x00, 0x02, 0x9A, 0x00, 0x00, 0x10, 0x8F, 0x82, 0x14, 0x03, 0x9A, 0x00, 0x01,
1875 0x00, 0x00, 0x00, 0x00, 0x02, 0x9A, 0x00, 0x00, 0x10, 0x8F, 0x02, 0x90, 0x00,
1876 0x9A, 0x00, 0x61, 0x00, 0x00, 0x00, 0x90, 0x00, 0x9A, 0x00, 0x7F, 0x00, 0x00,
1877 0xC0, 0x2E, 0x00, 0x02, 0x00, 0xE8, 0x03, 0x00, 0x00, 0x21, 0x00, 0x35, 0x00,
1878 0x98, 0x06, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9C, 0x06, 0x9A, 0x00, 0x00,
1879 0x00, 0x00, 0x00, 0x24, 0x08, 0x9A, 0x00, 0x85, 0x8F, 0x8B, 0xF7, 0x38, 0x1F,
1880 0x9A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x34, 0x1F, 0x9A, 0x00, 0x00, 0x00, 0x01,
1881 0x00, 0x34, 0x0D, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x08, 0x9A, 0x00,
1882 0xE7, 0x8F, 0x8B, 0xF7, 0x40, 0x0D, 0x9A, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x24,
1883 0x08, 0x9A, 0x00, 0xE7, 0x8F, 0x83, 0x40, 0x08, 0x08, 0x9A, 0x00, 0x70, 0x00,
1884 0xA0, 0x4A, 0x00, 0x02, 0x9A, 0x00, 0x00, 0x90, 0x8F, 0x02, 0x30, 0x08, 0x9A,
1885 0x00, 0x90, 0x20, 0x67, 0x01, 0x30, 0x08, 0x9A, 0x00, 0x90, 0x20, 0x67, 0x00,
1886 0xF4, 0x73, 0x13, 0x00, 0x12, 0x11, 0x00, 0x00, 0xF4, 0x73, 0x13, 0x00, 0x10,
1887 0x11, 0x00, 0x00, 0xF4, 0x73, 0x13, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x20,
1888 0x13, 0x00, 0x00, 0x00, 0x03, 0x98, 0x00, 0x20, 0x13, 0x00, 0x02, 0x00, 0x03,
1889 0x98, 0x20, 0x20, 0x13, 0x00, 0x00, 0x00, 0x03, 0x20, 0x20, 0x73, 0x13, 0x00,
1890 0x00, 0x00, 0x00, 0x00, 0x30, 0x20, 0x13, 0x00, 0x06, 0x00, 0x00, 0x10, 0x34,
1891 0x20, 0x13, 0x00, 0x00, 0x10, 0x67, 0x06, 0x24, 0x20, 0x13, 0x00, 0x01, 0x3B,
1892 0x02, 0x00, 0x2C, 0x20, 0x13, 0x00, 0x00, 0x01, 0x00, 0x00, 0x28, 0x20, 0x13,
1893 0x00, 0x10, 0x00, 0x08, 0x10, 0x20, 0x20, 0x13, 0x00, 0x01, 0x00, 0x03, 0x20,
1894 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x90,
1895 0x73, 0x13, 0x00, 0x15, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0xFA,
1896 0x00, 0x00, 0x21, 0x00, 0x25, 0x00, 0x2C, 0x20, 0x13, 0x00, 0x00, 0x03, 0x00,
1897 0x00, 0x28, 0x20, 0x13, 0x00, 0x10, 0x00, 0x04, 0x10, 0xF4, 0x73, 0x13, 0x00,
1898 0x00, 0x11, 0x01, 0x00, 0xF4, 0x73, 0x13, 0x00, 0x10, 0x11, 0x01, 0x00, 0xF0,
1899 0x73, 0x13, 0x00, 0x01, 0x00, 0x00, 0x00, 0xEC, 0x73, 0x13, 0x00, 0x00, 0x00,
1900 0x01, 0x00, 0xF4, 0x73, 0x13, 0x00, 0x11, 0x11, 0x01, 0x00, 0xF4, 0x73, 0x13,
1901 0x00, 0x11, 0x11, 0x00, 0x00, 0x30, 0x08, 0x9A, 0x00, 0x91, 0x20, 0x27, 0x00,
1902 0x5C, 0x06, 0x9A, 0x00, 0x11, 0x00, 0x00, 0x00, 0x70, 0x06, 0x9A, 0x00, 0x06,
1903 0x13, 0x08, 0xB4, 0x98, 0x06, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9C, 0x06,
1904 0x9A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x94, 0x06, 0x9A, 0x00, 0x0E, 0x06, 0x0E,
1905 0x06, 0x0C, 0x06, 0x9A, 0x00, 0x50, 0x20, 0x00, 0xFD, 0xD4, 0x0E, 0x9A, 0x00,
1906 0x00, 0x00, 0x00, 0x40, 0xD4, 0x0E, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24,
1907 0x08, 0x9A, 0x00, 0xE7, 0x8F, 0x80, 0x40, 0x13, 0x00, 0x02, 0x00, 0x2C, 0x01,
1908 0x00, 0x00, 0x2E, 0x00, 0x02, 0x00, 0x10, 0x27, 0x00, 0x00, 0x21, 0x00, 0x25,
1909 0x00, 0x70, 0x06, 0x9A, 0x00, 0x06, 0x13, 0x08, 0x34, 0x2C, 0x08, 0x9A, 0x00,
1910 0x00, 0x00, 0x15, 0x00, 0x30, 0x08, 0x9A, 0x00, 0x91, 0x10, 0x27, 0x00, 0x48,
1911 0x02, 0x9A, 0x00, 0xA3, 0x44, 0x14, 0x86, 0x90, 0x02, 0x9A, 0x00, 0x12, 0x2C,
1912 0x18, 0x06, 0x94, 0x02, 0x9A, 0x00, 0x8A, 0x82, 0x41, 0x24, 0x98, 0x02, 0x9A,
1913 0x00, 0x11, 0x05, 0x06, 0x88, 0x9C, 0x02, 0x9A, 0x00, 0x8C, 0x10, 0x00, 0x22,
1914 0xA0, 0x02, 0x9A, 0x00, 0x32, 0x00, 0x61, 0xD3, 0xA8, 0x02, 0x9A, 0x00, 0x0B,
1915 0x86, 0x00, 0x01, 0x14, 0x06, 0x9A, 0x00, 0x77, 0x3E, 0x03, 0x30, 0x10, 0x06,
1916 0x9A, 0x00, 0x77, 0x3E, 0x03, 0x30, 0x08, 0x08, 0x9A, 0x00, 0x70, 0x00, 0x00,
1917 0x48, 0x78, 0x07, 0x10, 0x00, 0x33, 0x03, 0x00, 0x82, 0x4C, 0x02, 0x9A, 0x00,
1918 0x85, 0x0C, 0x05, 0x06, 0x30, 0x1F, 0x9A, 0x00, 0x03, 0x16, 0x2C, 0x00, 0xE0,
1919 0x08, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0x9A, 0x00, 0x7E, 0x00,
1920 0x00, 0x40, 0x2E, 0x00, 0x02, 0x00, 0xD0, 0x07, 0x00, 0x00, 0x21, 0x00, 0x0D,
1921 0x00, 0x14, 0x03, 0x9A, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x03, 0x9A, 0x00,
1922 0x01, 0x00, 0x00, 0x00, 0x10, 0x02, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x80, 0x38,
1923 0x03, 0x9A, 0x00, 0x23, 0x01, 0x30, 0x00, 0x00, 0x03, 0x9A, 0x00, 0x2D, 0x02,
1924 0x00, 0x00, 0x54, 0x03, 0x9A, 0x00, 0x00, 0x00, 0x80, 0x00, 0x2E, 0x00, 0x02,
1925 0x00, 0xE8, 0x03, 0x00, 0x00, 0x21, 0x00, 0x09, 0x00, 0x30, 0x03, 0x9A, 0x00,
1926 0x30, 0x00, 0x10, 0x00, 0x48, 0x03, 0x9A, 0x00, 0x88, 0x00, 0x70, 0x00, 0x38,
1927 0xD6, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x04, 0xD6, 0x00, 0x00, 0x01, 0x00,
1928 0x00, 0x00, 0x2E, 0x00, 0x02, 0x00, 0x20, 0x4E, 0x00, 0x00, 0x21, 0x00, 0x07,
1929 0x00, 0x00, 0x02, 0x9A, 0x00, 0x00, 0x90, 0x8F, 0x82, 0x18, 0x03, 0x9A, 0x00,
1930 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x9A, 0x00, 0x00, 0x90, 0x8F, 0x02, 0x2E,
1931 0x00, 0x02, 0x00, 0xE8, 0x03, 0x00, 0x00, 0x21, 0x00, 0x0D, 0x00, 0x78, 0x09,
1932 0x9A, 0x00, 0x0B, 0x1E, 0x7A, 0x88, 0x30, 0x08, 0x9A, 0x00, 0x91, 0x10, 0x27,
1933 0x00, 0x10, 0x09, 0x90, 0x00, 0x00, 0x00, 0x0A, 0x98, 0x14, 0x09, 0x90, 0x00,
1934 0x00, 0x00, 0x0A, 0x98, 0x10, 0x49, 0x90, 0x00, 0x00, 0x00, 0x0A, 0x98, 0x14,
1935 0x49, 0x90, 0x00, 0x00, 0x00, 0x0A, 0x98, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
1936 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x74, 0x09, 0x90, 0x00, 0x15, 0x00, 0x03,
1937 0x00, 0x0F, 0x00, 0x00, 0x00, 0x20, 0xA1, 0x07, 0x00, 0x01, 0x00, 0x02, 0x00,
1938 0x74, 0x49, 0x90, 0x00, 0x15, 0x00, 0x03, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x20,
1939 0xA1, 0x07, 0x00, 0x21, 0x00, 0x0D, 0x00, 0x30, 0x08, 0x9A, 0x00, 0x91, 0x10,
1940 0x27, 0x01, 0x30, 0x08, 0x9A, 0x00, 0x91, 0x10, 0x27, 0x00, 0x10, 0x09, 0x90,
1941 0x00, 0x00, 0x00, 0x08, 0x19, 0x14, 0x09, 0x90, 0x00, 0x00, 0x00, 0x08, 0x19,
1942 0x10, 0x49, 0x90, 0x00, 0x00, 0x00, 0x08, 0x19, 0x14, 0x49, 0x90, 0x00, 0x00,
1943 0x00, 0x08, 0x19, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1944 0x00, 0x00, 0x34, 0x00, 0x02, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03,
1945 0x00, 0x00, 0x02, 0x9A, 0x00, 0x00, 0x98, 0x8F, 0x02, 0x16, 0x00, 0x02, 0x00,
1946 0x00, 0x00, 0x00, 0x00,
1947};
1948
1949#ifdef CONFIG_DEBUG_FS
1950static int mclk_debugfs_init(struct gk20a *g);
1951#endif
1952
1953static void mclk_memory_load_training_pattern(struct gk20a *g)
1954{
1955 u32 reg_writes;
1956 u32 index;
1957
1958 gk20a_dbg_info("");
1959
1960 reg_writes = ((sizeof(memory_pattern_reglist) /
1961 sizeof((memory_pattern_reglist)[0])));
1962
1963 for (index = 0; index < reg_writes; index++) {
1964 gk20a_writel(g, memory_pattern_reglist[index].regaddr,
1965 memory_pattern_reglist[index].writeval);
1966 }
1967
1968 gk20a_dbg_fn("done");
1969}
1970
1971static void mclk_seq_pmucmdhandler(struct gk20a *g, struct pmu_msg *_msg,
1972 void *param, u32 handle, u32 status)
1973{
1974 struct nv_pmu_seq_msg *msg = (struct nv_pmu_seq_msg *)_msg;
1975 struct nv_pmu_seq_msg_run_script *seq_msg;
1976 u32 msg_status = 0;
1977
1978 gk20a_dbg_info("");
1979
1980 if (status != 0) {
1981 gk20a_err(dev_from_gk20a(g), "mclk seq_script cmd aborted");
1982 msg_status = -ENOENT;
1983 goto status_update;
1984 }
1985
1986 seq_msg = &msg->run_script;
1987
1988 if (seq_msg->msg_type != NV_PMU_SEQ_MSG_ID_RUN_SCRIPT) {
1989 msg_status = -ENOENT;
1990 goto status_update;
1991 }
1992
1993 if (seq_msg->error_code) {
1994 msg_status = -ENOENT;
1995 goto status_update;
1996 }
1997
1998status_update:
1999 *((u32 *)param) = msg_status;
2000}
2001
2002static int mclk_get_memclk_table(struct gk20a *g)
2003{
2004 int status = 0;
2005 u8 *mem_table_ptr = NULL;
2006 u32 idx_to_ptr_tbl[8];
2007 u32 idx_to_cmd_ptr_tbl[8];
2008
2009 u32 old_fbio_delay;
2010 u32 old_fbio_cmd_delay;
2011
2012 u32 cmd_idx;
2013 u32 shadow_idx;
2014
2015 struct vbios_memory_clock_header_1x memclock_table_header = { 0 };
2016 struct vbios_memory_clock_base_entry_11 memclock_base_entry = { 0 };
2017
2018 u8 *mem_entry_ptr = NULL;
2019 int index;
2020
2021 gk20a_dbg_info("");
2022
2023 if (!(g->ops.bios.get_perf_table_ptrs &&
2024 g->ops.bios.execute_script)) {
2025 goto done;
2026 }
2027
2028 mem_table_ptr = (u8 *)g->ops.bios.get_perf_table_ptrs(g,
2029 g->bios.perf_token,
2030 MEMORY_CLOCK_TABLE);
2031 if (mem_table_ptr == NULL) {
2032 status = -EPERM;
2033 goto done;
2034 }
2035
2036 memcpy(&memclock_table_header, mem_table_ptr,
2037 sizeof(memclock_table_header));
2038
2039 if ((memclock_table_header.version <
2040 VBIOS_MEMORY_CLOCK_HEADER_11_VERSION) ||
2041 (memclock_table_header.base_entry_size <
2042 VBIOS_MEMORY_CLOCK_BASE_ENTRY_11_2_SIZE)) {
2043 status = -EINVAL;
2044 goto done;
2045 }
2046
2047 /* reset and save shadow table map and registers */
2048 old_fbio_delay = gk20a_readl(g, fb_fbpa_fbio_delay_r());
2049 old_fbio_cmd_delay = gk20a_readl(g, fb_fbpa_fbio_cmd_delay_r());
2050
2051 memset(idx_to_ptr_tbl, 0, sizeof(idx_to_ptr_tbl));
2052 memset(idx_to_cmd_ptr_tbl, 0, sizeof(idx_to_cmd_ptr_tbl));
2053
2054 /* Read table entries */
2055 mem_entry_ptr = mem_table_ptr + memclock_table_header.header_size;
2056 for (index = 0; index < memclock_table_header.entry_count; index++) {
2057 u8 script_index, cmd_script_index;
2058 u32 script_ptr = 0, cmd_script_ptr = 0;
2059
2060 memcpy(&memclock_base_entry, mem_entry_ptr,
2061 memclock_table_header.base_entry_size);
2062 if (memclock_base_entry.maximum == 0)
2063 continue;
2064
2065 script_index = BIOS_GET_FIELD(memclock_base_entry.flags1,
2066 VBIOS_MEMORY_CLOCK_BASE_ENTRY_11_FLAGS1_SCRIPT_INDEX);
2067
2068 script_ptr = gm206_bios_read_u32(g,
2069 memclock_table_header.script_list_ptr +
2070 script_index * sizeof(u32));
2071
2072 if (!script_ptr)
2073 continue;
2074
2075 /* Link and execute shadow scripts */
2076
2077 for (shadow_idx = 0; shadow_idx <= fb_fbpa_fbio_delay_priv_max_v();
2078 ++shadow_idx) {
2079 if (script_ptr == idx_to_ptr_tbl[shadow_idx]) {
2080 break;
2081 }
2082 }
2083
2084 /* script has not been executed before */
2085 if (shadow_idx > fb_fbpa_fbio_delay_priv_max_v()) {
2086 /* find unused index */
2087 for (shadow_idx = 0; shadow_idx <
2088 fb_fbpa_fbio_delay_priv_max_v();
2089 ++shadow_idx) {
2090 if (idx_to_ptr_tbl[shadow_idx] == 0)
2091 break;
2092 }
2093
2094 if (shadow_idx > fb_fbpa_fbio_delay_priv_max_v()) {
2095 gk20a_err(dev_from_gk20a(g),
2096 "invalid shadow reg script index");
2097 status = -EINVAL;
2098 goto done;
2099 }
2100
2101 idx_to_ptr_tbl[shadow_idx] = script_ptr;
2102
2103 gk20a_writel(g, fb_fbpa_fbio_delay_r(),
2104 set_field(old_fbio_delay,
2105 fb_fbpa_fbio_delay_priv_m(),
2106 fb_fbpa_fbio_delay_priv_f(shadow_idx)));
2107
2108 status = g->ops.bios.execute_script(g, script_ptr);
2109 if (status < 0) {
2110 gk20a_writel(g, fb_fbpa_fbio_delay_r(),
2111 old_fbio_delay);
2112 goto done;
2113 }
2114
2115 gk20a_writel(g, fb_fbpa_fbio_delay_r(), old_fbio_delay);
2116
2117 }
2118
2119 cmd_script_index = BIOS_GET_FIELD(memclock_base_entry.flags2,
2120 VBIOS_MEMORY_CLOCK_BASE_ENTRY_12_FLAGS2_CMD_SCRIPT_INDEX);
2121
2122 cmd_script_ptr = gm206_bios_read_u32(g,
2123 memclock_table_header.cmd_script_list_ptr +
2124 cmd_script_index * sizeof(u32));
2125
2126 if (!cmd_script_ptr)
2127 continue;
2128
2129 /* Link and execute cmd shadow scripts */
2130 for (cmd_idx = 0; cmd_idx <= fb_fbpa_fbio_cmd_delay_cmd_priv_max_v();
2131 ++cmd_idx) {
2132 if (cmd_script_ptr == idx_to_cmd_ptr_tbl[cmd_idx])
2133 break;
2134 }
2135
2136 /* script has not been executed before */
2137 if (cmd_idx > fb_fbpa_fbio_cmd_delay_cmd_priv_max_v()) {
2138 /* find unused index */
2139 for (cmd_idx = 0; cmd_idx <
2140 fb_fbpa_fbio_cmd_delay_cmd_priv_max_v();
2141 ++cmd_idx) {
2142 if (idx_to_cmd_ptr_tbl[cmd_idx] == 0)
2143 break;
2144 }
2145
2146 if (cmd_idx > fb_fbpa_fbio_cmd_delay_cmd_priv_max_v()) {
2147 gk20a_err(dev_from_gk20a(g),
2148 "invalid shadow reg cmd script index");
2149 status = -EINVAL;
2150 goto done;
2151 }
2152
2153 idx_to_cmd_ptr_tbl[cmd_idx] = cmd_script_ptr;
2154 gk20a_writel(g, fb_fbpa_fbio_cmd_delay_r(),
2155 set_field(old_fbio_cmd_delay,
2156 fb_fbpa_fbio_cmd_delay_cmd_priv_m(),
2157 fb_fbpa_fbio_cmd_delay_cmd_priv_f(
2158 cmd_idx)));
2159
2160 status = g->ops.bios.execute_script(g, cmd_script_ptr);
2161 if (status < 0) {
2162 gk20a_writel(g, fb_fbpa_fbio_cmd_delay_r(),
2163 old_fbio_cmd_delay);
2164 goto done;
2165 }
2166
2167 gk20a_writel(g, fb_fbpa_fbio_cmd_delay_r(),
2168 old_fbio_cmd_delay);
2169
2170 }
2171
2172 mem_entry_ptr += memclock_table_header.base_entry_size +
2173 memclock_table_header.strap_entry_count *
2174 memclock_table_header.strap_entry_size;
2175 }
2176
2177done:
2178 return status;
2179}
2180
2181int clk_mclkseq_init_mclk_gddr5(struct gk20a *g)
2182{
2183 struct clk_mclk_state *mclk;
2184 int status;
2185 struct clk_set_info *p5_info;
2186 struct clk_set_info *p0_info;
2187
2188
2189 gk20a_dbg_fn("");
2190
2191 mclk = &g->clk_pmu.clk_mclk;
2192
2193 mutex_init(&mclk->mclk_lock);
2194 mutex_init(&mclk->data_lock);
2195
2196 /* FBPA gain WAR */
2197 gk20a_writel(g, fb_fbpa_fbio_iref_byte_rx_ctrl_r(), 0x22222222);
2198
2199 mclk->speed = gk20a_mclk_low_speed; /* Value from Devinit */
2200
2201 /* Parse VBIOS */
2202 status = mclk_get_memclk_table(g);
2203 if (status < 0)
2204 return status;
2205
2206 /* Load RAM pattern */
2207 mclk_memory_load_training_pattern(g);
2208
2209 p5_info = pstate_get_clk_set_info(g,
2210 CTRL_PERF_PSTATE_P5, clkwhich_mclk);
2211 if (!p5_info)
2212 return -EINVAL;
2213
2214 p0_info = pstate_get_clk_set_info(g,
2215 CTRL_PERF_PSTATE_P0, clkwhich_mclk);
2216 if (!p0_info)
2217 return -EINVAL;
2218
2219
2220 mclk->p5_min = p5_info->min_mhz;
2221 mclk->p0_min = p0_info->min_mhz;
2222
2223
2224 mclk->vreg_buf = kcalloc(VREG_COUNT,
2225 sizeof(u32), GFP_KERNEL);
2226 if (!mclk->vreg_buf) {
2227 gk20a_err(dev_from_gk20a(g),
2228 "unable to allocate memory for VREG");
2229 return -ENOMEM;
2230 }
2231
2232#ifdef CONFIG_DEBUG_FS
2233 if (!mclk->debugfs_set) {
2234 if (mclk_debugfs_init(g))
2235 mclk->debugfs_set = true;
2236 }
2237#endif
2238 mclk->change = clk_mclkseq_change_mclk_gddr5;
2239
2240 mclk->init = true;
2241
2242 return 0;
2243}
2244
2245int clk_mclkseq_change_mclk_gddr5(struct gk20a *g, u16 val)
2246{
2247 struct clk_mclk_state *mclk;
2248 struct pmu_payload payload = { {0} };
2249 struct nv_pmu_seq_cmd cmd;
2250 struct nv_pmu_seq_cmd_run_script *pseq_cmd;
2251 u32 seqdesc;
2252 int status = 0;
2253 u32 seq_completion_status = ~0x0;
2254 u8 *seq_script_ptr = NULL;
2255 size_t seq_script_size = 0;
2256#ifdef CONFIG_DEBUG_FS
2257 u64 t0, t1;
2258#endif
2259 enum gk20a_mclk_speed speed;
2260
2261 gk20a_dbg_info("");
2262
2263 mclk = &g->clk_pmu.clk_mclk;
2264
2265 mutex_lock(&mclk->mclk_lock);
2266
2267 if (!mclk->init)
2268 goto exit_status;
2269
2270 speed = (val < mclk->p5_min) ? gk20a_mclk_low_speed :
2271 (val < mclk->p0_min) ? gk20a_mclk_mid_speed :
2272 gk20a_mclk_high_speed;
2273
2274
2275 if (speed == mclk->speed)
2276 goto exit_status;
2277
2278 switch (speed) {
2279 case gk20a_mclk_mid_speed:
2280 if (mclk->speed == gk20a_mclk_low_speed) {
2281 seq_script_ptr = seq_script_step33_gp106;
2282 seq_script_size = sizeof(seq_script_step33_gp106);
2283 } else {
2284 seq_script_ptr = seq_script_step32_gp106;
2285 seq_script_size = sizeof(seq_script_step32_gp106);
2286 }
2287 break;
2288 case gk20a_mclk_high_speed:
2289 seq_script_ptr = seq_script_step28_gp106;
2290 seq_script_size = sizeof(seq_script_step28_gp106);
2291 break;
2292 case gk20a_mclk_low_speed:
2293 if (mclk->speed == gk20a_mclk_mid_speed) {
2294 seq_script_ptr = seq_script_step33_ls_gp106;
2295 seq_script_size = sizeof(seq_script_step33_ls_gp106);
2296 } else {
2297 seq_script_ptr = seq_script_step32_ls_gp106;
2298 seq_script_size = sizeof(seq_script_step32_ls_gp106);
2299 }
2300 break;
2301 default:
2302 gk20a_err(dev_from_gk20a(g),
2303 "Illegal MCLK clock change");
2304 status = -EINVAL;
2305 goto exit_status;
2306 }
2307
2308 /* Fill command header with SEQ ID & size */
2309 memset(&cmd, 0, sizeof(cmd));
2310 cmd.hdr.unit_id = PMU_UNIT_SEQ;
2311 cmd.hdr.size = sizeof(struct nv_pmu_seq_cmd_run_script) +
2312 sizeof(struct pmu_hdr);
2313
2314 /* Fill RM_PMU_SEQ_CMD_RUN_SCRIPT struct */
2315 pseq_cmd = &cmd.run_script;
2316 pseq_cmd->cmd_type = NV_PMU_SEQ_CMD_ID_RUN_SCRIPT;
2317
2318#ifdef CONFIG_DEBUG_FS
2319 g->ops.read_ptimer(g, &t0);
2320#endif
2321
2322 if (speed == gk20a_mclk_high_speed) {
2323 gk20a_writel(g, 0x132000, 0x98010000);
2324 /* Introduce delay */
2325 gk20a_readl(g, 0x132000);
2326 gk20a_readl(g, 0x132000);
2327 }
2328
2329 gk20a_writel(g, 0x137300, 0x20000103);
2330
2331 /* Read sequencer binary*/
2332 payload.in.buf = seq_script_ptr;
2333 payload.in.size = seq_script_size;
2334 payload.in.fb_size = PMU_CMD_SUBMIT_PAYLOAD_PARAMS_FB_SIZE_UNUSED;
2335 payload.in.offset = offsetof(struct nv_pmu_seq_cmd_run_script,
2336 script_alloc);
2337
2338 memset(mclk->vreg_buf, 0, (sizeof(u32) * VREG_COUNT));
2339
2340 payload.out.buf = mclk->vreg_buf;
2341 payload.out.size = (VREG_COUNT * sizeof(u32));
2342 payload.out.fb_size = PMU_CMD_SUBMIT_PAYLOAD_PARAMS_FB_SIZE_UNUSED;
2343 payload.out.offset = offsetof(struct nv_pmu_seq_cmd_run_script,
2344 reg_alloc);
2345
2346 /* Send command to PMU to execute sequencer script */
2347 status = gk20a_pmu_cmd_post(g, (struct pmu_cmd *)&cmd, NULL, &payload,
2348 PMU_COMMAND_QUEUE_LPQ,
2349 mclk_seq_pmucmdhandler,
2350 &seq_completion_status, &seqdesc, ~0);
2351 if (status) {
2352 gk20a_err(dev_from_gk20a(g),
2353 "unable to post seq script exec cmd for unit %x ",
2354 cmd.hdr.unit_id);
2355 goto exit_status;
2356 }
2357 /* wait till sequencer script complete */
2358 pmu_wait_message_cond(&g->pmu, (gk20a_get_gr_idle_timeout(g)),
2359 &seq_completion_status, 0);
2360 if (seq_completion_status != 0) {
2361 gk20a_err(dev_from_gk20a(g),
2362 "seq_script update failed");
2363 status = -EBUSY;
2364 goto exit_status;
2365 }
2366
2367 mclk->speed = speed;
2368
2369#ifdef CONFIG_DEBUG_FS
2370 g->ops.read_ptimer(g, &t1);
2371
2372 mutex_lock(&mclk->data_lock);
2373 mclk->switch_num++;
2374
2375 if (mclk->switch_num == 1) {
2376 mclk->switch_max = mclk->switch_min =
2377 mclk->switch_avg = (t1-t0)/1000;
2378 mclk->switch_std = 0;
2379 } else {
2380 s64 prev_avg;
2381 s64 curr = (t1-t0)/1000;
2382
2383 mclk->switch_max = curr > mclk->switch_max ?
2384 curr : mclk->switch_max;
2385 mclk->switch_min = mclk->switch_min ?
2386 (curr < mclk->switch_min ?
2387 curr : mclk->switch_min) : curr;
2388 prev_avg = mclk->switch_avg;
2389 mclk->switch_avg = (curr +
2390 (mclk->switch_avg * (mclk->switch_num-1))) /
2391 mclk->switch_num;
2392 mclk->switch_std +=
2393 (curr - mclk->switch_avg) * (curr - prev_avg);
2394 }
2395 mutex_unlock(&mclk->data_lock);
2396#endif
2397exit_status:
2398
2399 mutex_unlock(&mclk->mclk_lock);
2400 return status;
2401}
2402
2403#ifdef CONFIG_DEBUG_FS
2404static int mclk_debug_speed_set(void *data, u64 val)
2405{
2406 struct gk20a *g = (struct gk20a *) data;
2407 struct clk_mclk_state *mclk;
2408
2409 mclk = &g->clk_pmu.clk_mclk;
2410
2411 /* This is problematic because it can interrupt the arbiter
2412 * and send it to sleep. we need to consider removing this
2413 */
2414 if (mclk->change)
2415 return mclk->change(g, (u16) val);
2416 return 0;
2417
2418}
2419
2420DEFINE_SIMPLE_ATTRIBUTE(
2421 mclk_debug_speed_set_fops,
2422 NULL,
2423 mclk_debug_speed_set,
2424 "%llu\n"
2425);
2426
2427static int mclk_switch_stats_show(struct seq_file *s, void *unused)
2428{
2429 struct gk20a *g = s->private;
2430 struct clk_mclk_state *mclk;
2431 u64 num;
2432 s64 tmp, avg, std, max, min;
2433
2434 mclk = &g->clk_pmu.clk_mclk;
2435
2436 /* Make copy of structure to reduce time with lock held */
2437 mutex_lock(&mclk->data_lock);
2438 std = mclk->switch_std;
2439 avg = mclk->switch_avg;
2440 max = mclk->switch_max;
2441 min = mclk->switch_min;
2442 num = mclk->switch_num;
2443 mutex_unlock(&mclk->data_lock);
2444
2445 tmp = std;
2446 do_div(tmp, num);
2447 seq_printf(s, "MCLK:\n number of transitions: %lld\n",
2448 num);
2449 seq_printf(s, "max / min : %lld / %lld usec\n",
2450 max, min);
2451 seq_printf(s, "avg / std : %lld / %ld usec\n",
2452 avg, int_sqrt(tmp));
2453
2454 return 0;
2455}
2456
2457static int mclk_switch_stats_open(struct inode *inode, struct file *file)
2458{
2459 return single_open(file, mclk_switch_stats_show, inode->i_private);
2460}
2461
2462static const struct file_operations mclk_switch_stats_fops = {
2463 .open = mclk_switch_stats_open,
2464 .read = seq_read,
2465 .llseek = seq_lseek,
2466 .release = single_release,
2467};
2468
2469
2470static int mclk_debugfs_init(struct gk20a *g)
2471{
2472 struct gk20a_platform *platform = dev_get_drvdata(g->dev);
2473
2474 struct dentry *gpu_root = platform->debugfs;
2475 struct dentry *d;
2476
2477 gk20a_dbg(gpu_dbg_info, "g=%p", g);
2478
2479 d = debugfs_create_file(
2480 "mclk_speed_set",
2481 S_IWUGO,
2482 gpu_root,
2483 g,
2484 &mclk_debug_speed_set_fops);
2485 if (!d)
2486 return -ENOMEM;
2487
2488 d = debugfs_create_file(
2489 "mclk_switch_stats",
2490 S_IRUGO,
2491 gpu_root,
2492 g,
2493 &mclk_switch_stats_fops);
2494 if (!d)
2495 return -ENOMEM;
2496
2497 return 0;
2498}
2499#endif
diff --git a/drivers/gpu/nvgpu/clk/clk_mclk.h b/drivers/gpu/nvgpu/clk/clk_mclk.h
new file mode 100644
index 00000000..cb7f0de0
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk_mclk.h
@@ -0,0 +1,52 @@
1/*
2* Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
3*
4* This program is free software; you can redistribute it and/or modify it
5* under the terms and conditions of the GNU General Public License,
6* version 2, as published by the Free Software Foundation.
7*
8* This program is distributed in the hope it will be useful, but WITHOUT
9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11* more details.
12*/
13
14#ifndef _CLKMCLK_H_
15#define _CLKMCLK_H_
16
17#include <linux/mutex.h>
18
19enum gk20a_mclk_speed {
20 gk20a_mclk_low_speed,
21 gk20a_mclk_mid_speed,
22 gk20a_mclk_high_speed,
23};
24
25struct clk_mclk_state {
26 enum gk20a_mclk_speed speed;
27 struct mutex mclk_lock;
28 struct mutex data_lock;
29
30 u16 p5_min;
31 u16 p0_min;
32
33 void *vreg_buf;
34 bool init;
35
36 /* function pointers */
37 int (*change)(struct gk20a *g, u16 val);
38
39#ifdef CONFIG_DEBUG_FS
40 s64 switch_max;
41 s64 switch_min;
42 u64 switch_num;
43 s64 switch_avg;
44 s64 switch_std;
45 bool debugfs_set;
46#endif
47};
48
49int clk_mclkseq_init_mclk_gddr5(struct gk20a *g);
50int clk_mclkseq_change_mclk_gddr5(struct gk20a *g, u16 val);
51
52#endif
diff --git a/drivers/gpu/nvgpu/clk/clk_prog.c b/drivers/gpu/nvgpu/clk/clk_prog.c
new file mode 100644
index 00000000..6b81650e
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk_prog.c
@@ -0,0 +1,1098 @@
1/*
2 * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 */
13
14#include "gk20a/gk20a.h"
15#include "clk.h"
16#include "clk_prog.h"
17#include "clk_vf_point.h"
18#include "include/bios.h"
19#include "boardobj/boardobjgrp.h"
20#include "boardobj/boardobjgrp_e32.h"
21#include "pmuif/gpmuifboardobj.h"
22#include "pmuif/gpmuifclk.h"
23#include "gm206/bios_gm206.h"
24#include "ctrl/ctrlclk.h"
25#include "ctrl/ctrlvolt.h"
26#include "gk20a/pmu_gk20a.h"
27
28static struct clk_prog *construct_clk_prog(struct gk20a *g, void *pargs);
29static u32 devinit_get_clk_prog_table(struct gk20a *g,
30 struct clk_progs *pprogobjs);
31static vf_flatten vfflatten_prog_1x_master;
32static vf_lookup vflookup_prog_1x_master;
33static get_fpoints getfpoints_prog_1x_master;
34static get_slaveclk getslaveclk_prog_1x_master;
35
36static u32 _clk_progs_pmudatainit(struct gk20a *g,
37 struct boardobjgrp *pboardobjgrp,
38 struct nv_pmu_boardobjgrp_super *pboardobjgrppmu)
39{
40 struct nv_pmu_clk_clk_prog_boardobjgrp_set_header *pset =
41 (struct nv_pmu_clk_clk_prog_boardobjgrp_set_header *)
42 pboardobjgrppmu;
43 struct clk_progs *pprogs = (struct clk_progs *)pboardobjgrp;
44 u32 status = 0;
45
46 status = boardobjgrp_pmudatainit_e32(g, pboardobjgrp, pboardobjgrppmu);
47 if (status) {
48 gk20a_err(dev_from_gk20a(g),
49 "error updating pmu boardobjgrp for clk prog 0x%x",
50 status);
51 goto done;
52 }
53 pset->slave_entry_count = pprogs->slave_entry_count;
54 pset->vf_entry_count = pprogs->vf_entry_count;
55
56done:
57 return status;
58}
59
60static u32 _clk_progs_pmudata_instget(struct gk20a *g,
61 struct nv_pmu_boardobjgrp *pmuboardobjgrp,
62 struct nv_pmu_boardobj **ppboardobjpmudata,
63 u8 idx)
64{
65 struct nv_pmu_clk_clk_prog_boardobj_grp_set *pgrp_set =
66 (struct nv_pmu_clk_clk_prog_boardobj_grp_set *)pmuboardobjgrp;
67
68 gk20a_dbg_info("");
69
70 /*check whether pmuboardobjgrp has a valid boardobj in index*/
71 if (((u32)BIT(idx) &
72 pgrp_set->hdr.data.super.obj_mask.super.data[0]) == 0)
73 return -EINVAL;
74
75 *ppboardobjpmudata = (struct nv_pmu_boardobj *)
76 &pgrp_set->objects[idx].data.board_obj;
77 gk20a_dbg_info(" Done");
78 return 0;
79}
80
81u32 clk_prog_sw_setup(struct gk20a *g)
82{
83 u32 status;
84 struct boardobjgrp *pboardobjgrp = NULL;
85 struct clk_progs *pclkprogobjs;
86
87 gk20a_dbg_info("");
88
89 status = boardobjgrpconstruct_e255(&g->clk_pmu.clk_progobjs.super);
90 if (status) {
91 gk20a_err(dev_from_gk20a(g),
92 "error creating boardobjgrp for clk prog, status - 0x%x",
93 status);
94 goto done;
95 }
96
97 pboardobjgrp = &g->clk_pmu.clk_progobjs.super.super;
98 pclkprogobjs = &(g->clk_pmu.clk_progobjs);
99
100 BOARDOBJGRP_PMU_CONSTRUCT(pboardobjgrp, CLK, CLK_PROG);
101
102 status = BOARDOBJGRP_PMU_CMD_GRP_SET_CONSTRUCT(g, pboardobjgrp,
103 clk, CLK, clk_prog, CLK_PROG);
104 if (status) {
105 gk20a_err(dev_from_gk20a(g),
106 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
107 status);
108 goto done;
109 }
110
111 pboardobjgrp->pmudatainit = _clk_progs_pmudatainit;
112 pboardobjgrp->pmudatainstget = _clk_progs_pmudata_instget;
113
114 status = devinit_get_clk_prog_table(g, pclkprogobjs);
115 if (status)
116 goto done;
117
118 status = clk_domain_clk_prog_link(g, &g->clk_pmu);
119 if (status) {
120 gk20a_err(dev_from_gk20a(g),
121 "error constructing VF point board objects");
122 goto done;
123 }
124
125
126done:
127 gk20a_dbg_info(" done status %x", status);
128 return status;
129}
130
131u32 clk_prog_pmu_setup(struct gk20a *g)
132{
133 u32 status;
134 struct boardobjgrp *pboardobjgrp = NULL;
135
136 gk20a_dbg_info("");
137
138 pboardobjgrp = &g->clk_pmu.clk_progobjs.super.super;
139
140 if (!pboardobjgrp->bconstructed)
141 return -EINVAL;
142
143 status = pboardobjgrp->pmuinithandle(g, pboardobjgrp);
144
145 gk20a_dbg_info("Done");
146 return status;
147}
148
149static u32 devinit_get_clk_prog_table(struct gk20a *g,
150 struct clk_progs *pclkprogobjs)
151{
152 u32 status = 0;
153 u8 *clkprogs_tbl_ptr = NULL;
154 struct vbios_clock_programming_table_1x_header header = { 0 };
155 struct vbios_clock_programming_table_1x_entry prog = { 0 };
156 struct vbios_clock_programming_table_1x_slave_entry slaveprog = { 0 };
157 struct vbios_clock_programming_table_1x_vf_entry vfprog = { 0 };
158 u8 *entry = NULL;
159 u8 *slaveentry = NULL;
160 u8 *vfentry = NULL;
161 u32 i, j = 0;
162 struct clk_prog *pprog;
163 u8 prog_type;
164 u32 szfmt = VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_SIZE_0D;
165 u32 hszfmt = VBIOS_CLOCK_PROGRAMMING_TABLE_1X_HEADER_SIZE_08;
166 u32 slaveszfmt = VBIOS_CLOCK_PROGRAMMING_TABLE_1X_SLAVE_ENTRY_SIZE_03;
167 u32 vfszfmt = VBIOS_CLOCK_PROGRAMMING_TABLE_1X_VF_ENTRY_SIZE_02;
168 struct ctrl_clk_clk_prog_1x_master_vf_entry
169 vfentries[CTRL_CLK_CLK_PROG_1X_MASTER_VF_ENTRY_MAX_ENTRIES];
170 struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry
171 ratioslaveentries[CTRL_CLK_PROG_1X_MASTER_MAX_SLAVE_ENTRIES];
172 struct ctrl_clk_clk_prog_1x_master_table_slave_entry
173 tableslaveentries[CTRL_CLK_PROG_1X_MASTER_MAX_SLAVE_ENTRIES];
174 union {
175 struct boardobj board_obj;
176 struct clk_prog clkprog;
177 struct clk_prog_1x v1x;
178 struct clk_prog_1x_master v1x_master;
179 struct clk_prog_1x_master_ratio v1x_master_ratio;
180 struct clk_prog_1x_master_table v1x_master_table;
181 } prog_data;
182
183 gk20a_dbg_info("");
184
185 if (g->ops.bios.get_perf_table_ptrs) {
186 clkprogs_tbl_ptr = (u8 *)g->ops.bios.get_perf_table_ptrs(g,
187 g->bios.clock_token, CLOCK_PROGRAMMING_TABLE);
188 if (clkprogs_tbl_ptr == NULL) {
189 status = -EINVAL;
190 goto done;
191 }
192 }
193
194 memcpy(&header, clkprogs_tbl_ptr, hszfmt);
195 if (header.header_size < hszfmt) {
196 status = -EINVAL;
197 goto done;
198 }
199 hszfmt = header.header_size;
200
201 if (header.entry_size <= VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_SIZE_05)
202 szfmt = header.entry_size;
203 else if (header.entry_size <= VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_SIZE_0D)
204 szfmt = header.entry_size;
205 else {
206 status = -EINVAL;
207 goto done;
208 }
209
210 if (header.vf_entry_size < vfszfmt) {
211 status = -EINVAL;
212 goto done;
213 }
214 vfszfmt = header.vf_entry_size;
215 if (header.slave_entry_size < slaveszfmt) {
216 status = -EINVAL;
217 goto done;
218 }
219 slaveszfmt = header.slave_entry_size;
220 if (header.vf_entry_count > CTRL_CLK_CLK_DELTA_MAX_VOLT_RAILS) {
221 status = -EINVAL;
222 goto done;
223 }
224
225 pclkprogobjs->slave_entry_count = header.slave_entry_count;
226 pclkprogobjs->vf_entry_count = header.vf_entry_count;
227
228 for (i = 0; i < header.entry_count; i++) {
229 memset(&prog_data, 0x0, (u32)sizeof(prog_data));
230
231 /* Read table entries*/
232 entry = clkprogs_tbl_ptr + hszfmt +
233 (i * (szfmt + (header.slave_entry_count * slaveszfmt) +
234 (header.vf_entry_count * vfszfmt)));
235
236 memcpy(&prog, entry, szfmt);
237 memset(vfentries, 0xFF,
238 sizeof(struct ctrl_clk_clk_prog_1x_master_vf_entry) *
239 CTRL_CLK_CLK_PROG_1X_MASTER_VF_ENTRY_MAX_ENTRIES);
240 memset(ratioslaveentries, 0xFF,
241 sizeof(struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry) *
242 CTRL_CLK_PROG_1X_MASTER_MAX_SLAVE_ENTRIES);
243 memset(tableslaveentries, 0xFF,
244 sizeof(struct ctrl_clk_clk_prog_1x_master_table_slave_entry) *
245 CTRL_CLK_PROG_1X_MASTER_MAX_SLAVE_ENTRIES);
246 prog_type = (u8)BIOS_GET_FIELD(prog.flags0,
247 NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_SOURCE);
248
249 switch (prog_type) {
250 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_SOURCE_PLL:
251 prog_data.v1x.source = CTRL_CLK_PROG_1X_SOURCE_PLL;
252 prog_data.v1x.source_data.pll.pll_idx =
253 (u8)BIOS_GET_FIELD(prog.param0,
254 NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_PARAM0_PLL_PLL_INDEX);
255 prog_data.v1x.source_data.pll.freq_step_size_mhz =
256 (u8)BIOS_GET_FIELD(prog.param1,
257 NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_PARAM1_PLL_FREQ_STEP_SIZE);
258 break;
259
260 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_SOURCE_ONE_SOURCE:
261 prog_data.v1x.source = CTRL_CLK_PROG_1X_SOURCE_ONE_SOURCE;
262 break;
263
264 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_SOURCE_FLL:
265 prog_data.v1x.source = CTRL_CLK_PROG_1X_SOURCE_FLL;
266 break;
267
268 default:
269 gk20a_err(dev_from_gk20a(g),
270 "invalid source %d", prog_type);
271 status = -EINVAL;
272 goto done;
273 }
274
275 prog_data.v1x.freq_max_mhz = (u16)prog.freq_max_mhz;
276
277 prog_type = (u8)BIOS_GET_FIELD(prog.flags0,
278 NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE);
279
280 vfentry = entry + szfmt +
281 header.slave_entry_count * slaveszfmt;
282 slaveentry = entry + szfmt;
283 switch (prog_type) {
284 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE_MASTER_RATIO:
285 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE_MASTER_TABLE:
286 prog_data.v1x_master.b_o_c_o_v_enabled = false;
287 for (j = 0; j < header.vf_entry_count; j++) {
288 memcpy(&vfprog, vfentry, vfszfmt);
289
290 vfentries[j].vfe_idx = (u8)vfprog.vfe_idx;
291 if (CTRL_CLK_PROG_1X_SOURCE_FLL ==
292 prog_data.v1x.source) {
293 vfentries[j].gain_vfe_idx = (u8)BIOS_GET_FIELD(
294 vfprog.param0,
295 NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_VF_ENTRY_PARAM0_FLL_GAIN_VFE_IDX);
296 } else {
297 vfentries[j].gain_vfe_idx = CTRL_BOARDOBJ_IDX_INVALID;
298 }
299 vfentry += vfszfmt;
300 }
301
302 prog_data.v1x_master.p_vf_entries = vfentries;
303
304 for (j = 0; j < header.slave_entry_count; j++) {
305 memcpy(&slaveprog, slaveentry, slaveszfmt);
306
307 switch (prog_type) {
308 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE_MASTER_RATIO:
309 ratioslaveentries[j].clk_dom_idx =
310 (u8)slaveprog.clk_dom_idx;
311 ratioslaveentries[j].ratio = (u8)
312 BIOS_GET_FIELD(slaveprog.param0,
313 NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_SLAVE_ENTRY_PARAM0_MASTER_RATIO_RATIO);
314 break;
315
316 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE_MASTER_TABLE:
317 tableslaveentries[j].clk_dom_idx =
318 (u8)slaveprog.clk_dom_idx;
319 tableslaveentries[j].freq_mhz =
320 (u16)BIOS_GET_FIELD(slaveprog.param0,
321 NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_SLAVE_ENTRY_PARAM0_MASTER_TABLE_FREQ);
322 break;
323 }
324 slaveentry += slaveszfmt;
325 }
326
327 switch (prog_type) {
328 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE_MASTER_RATIO:
329 prog_data.board_obj.type = CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_RATIO;
330 prog_data.v1x_master_ratio.p_slave_entries =
331 ratioslaveentries;
332 break;
333
334 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE_MASTER_TABLE:
335 prog_data.board_obj.type = CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_TABLE;
336
337 prog_data.v1x_master_table.p_slave_entries =
338 tableslaveentries;
339 break;
340
341 }
342 break;
343
344 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE_SLAVE:
345 prog_data.board_obj.type = CTRL_CLK_CLK_PROG_TYPE_1X;
346 break;
347
348
349 default:
350 gk20a_err(dev_from_gk20a(g),
351 "source issue %d", prog_type);
352 status = -EINVAL;
353 goto done;
354 }
355
356 pprog = construct_clk_prog(g, (void *)&prog_data);
357 if (pprog == NULL) {
358 gk20a_err(dev_from_gk20a(g),
359 "error constructing clk_prog boardobj %d", i);
360 status = -EINVAL;
361 goto done;
362 }
363
364 status = boardobjgrp_objinsert(&pclkprogobjs->super.super,
365 (struct boardobj *)pprog, i);
366 if (status) {
367 gk20a_err(dev_from_gk20a(g),
368 "error adding clk_prog boardobj %d", i);
369 status = -EINVAL;
370 goto done;
371 }
372 }
373done:
374 gk20a_dbg_info(" done status %x", status);
375 return status;
376}
377
378static u32 _clk_prog_pmudatainit_super(struct gk20a *g,
379 struct boardobj *board_obj_ptr,
380 struct nv_pmu_boardobj *ppmudata)
381{
382 u32 status = 0;
383
384 gk20a_dbg_info("");
385
386 status = boardobj_pmudatainit_super(g, board_obj_ptr, ppmudata);
387 return status;
388}
389
390static u32 _clk_prog_pmudatainit_1x(struct gk20a *g,
391 struct boardobj *board_obj_ptr,
392 struct nv_pmu_boardobj *ppmudata)
393{
394 u32 status = 0;
395 struct clk_prog_1x *pclk_prog_1x;
396 struct nv_pmu_clk_clk_prog_1x_boardobj_set *pset;
397
398 gk20a_dbg_info("");
399
400 status = _clk_prog_pmudatainit_super(g, board_obj_ptr, ppmudata);
401 if (status != 0)
402 return status;
403
404 pclk_prog_1x = (struct clk_prog_1x *)board_obj_ptr;
405
406 pset = (struct nv_pmu_clk_clk_prog_1x_boardobj_set *)
407 ppmudata;
408
409 pset->source = pclk_prog_1x->source;
410 pset->freq_max_mhz = pclk_prog_1x->freq_max_mhz;
411 pset->source_data = pclk_prog_1x->source_data;
412
413 return status;
414}
415
416static u32 _clk_prog_pmudatainit_1x_master(struct gk20a *g,
417 struct boardobj *board_obj_ptr,
418 struct nv_pmu_boardobj *ppmudata)
419{
420 u32 status = 0;
421 struct clk_prog_1x_master *pclk_prog_1x_master;
422 struct nv_pmu_clk_clk_prog_1x_master_boardobj_set *pset;
423 u32 vfsize = sizeof(struct ctrl_clk_clk_prog_1x_master_vf_entry) *
424 g->clk_pmu.clk_progobjs.vf_entry_count;
425
426 gk20a_dbg_info("");
427
428 status = _clk_prog_pmudatainit_1x(g, board_obj_ptr, ppmudata);
429
430 pclk_prog_1x_master =
431 (struct clk_prog_1x_master *)board_obj_ptr;
432
433 pset = (struct nv_pmu_clk_clk_prog_1x_master_boardobj_set *)
434 ppmudata;
435
436 memcpy(pset->vf_entries, pclk_prog_1x_master->p_vf_entries, vfsize);
437
438 pset->b_o_c_o_v_enabled = pclk_prog_1x_master->b_o_c_o_v_enabled;
439 pset->source_data = pclk_prog_1x_master->source_data;
440
441 memcpy(&pset->deltas, &pclk_prog_1x_master->deltas,
442 (u32) sizeof(struct ctrl_clk_clk_delta));
443
444 return status;
445}
446
447static u32 _clk_prog_pmudatainit_1x_master_ratio(struct gk20a *g,
448 struct boardobj *board_obj_ptr,
449 struct nv_pmu_boardobj *ppmudata)
450{
451 u32 status = 0;
452 struct clk_prog_1x_master_ratio *pclk_prog_1x_master_ratio;
453 struct nv_pmu_clk_clk_prog_1x_master_ratio_boardobj_set *pset;
454 u32 slavesize = sizeof(struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry) *
455 g->clk_pmu.clk_progobjs.slave_entry_count;
456
457 gk20a_dbg_info("");
458
459 status = _clk_prog_pmudatainit_1x_master(g, board_obj_ptr, ppmudata);
460 if (status != 0)
461 return status;
462
463 pclk_prog_1x_master_ratio =
464 (struct clk_prog_1x_master_ratio *)board_obj_ptr;
465
466 pset = (struct nv_pmu_clk_clk_prog_1x_master_ratio_boardobj_set *)
467 ppmudata;
468
469 memcpy(pset->slave_entries,
470 pclk_prog_1x_master_ratio->p_slave_entries, slavesize);
471
472 return status;
473}
474
475static u32 _clk_prog_pmudatainit_1x_master_table(struct gk20a *g,
476 struct boardobj *board_obj_ptr,
477 struct nv_pmu_boardobj *ppmudata)
478{
479 u32 status = 0;
480 struct clk_prog_1x_master_table *pclk_prog_1x_master_table;
481 struct nv_pmu_clk_clk_prog_1x_master_table_boardobj_set *pset;
482 u32 slavesize = sizeof(struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry) *
483 g->clk_pmu.clk_progobjs.slave_entry_count;
484
485 gk20a_dbg_info("");
486
487 status = _clk_prog_pmudatainit_1x_master(g, board_obj_ptr, ppmudata);
488 if (status != 0)
489 return status;
490
491 pclk_prog_1x_master_table =
492 (struct clk_prog_1x_master_table *)board_obj_ptr;
493
494 pset = (struct nv_pmu_clk_clk_prog_1x_master_table_boardobj_set *)
495 ppmudata;
496 memcpy(pset->slave_entries,
497 pclk_prog_1x_master_table->p_slave_entries, slavesize);
498
499 return status;
500}
501
502static u32 _clk_prog_1x_master_rail_construct_vf_point(struct gk20a *g,
503 struct clk_pmupstate *pclk,
504 struct clk_prog_1x_master *p1xmaster,
505 struct ctrl_clk_clk_prog_1x_master_vf_entry *p_vf_rail,
506 struct clk_vf_point *p_vf_point_tmp,
507 u8 *p_vf_point_idx)
508{
509 struct clk_vf_point *p_vf_point;
510 u32 status;
511
512 gk20a_dbg_info("");
513
514 p_vf_point = construct_clk_vf_point(g, (void *)p_vf_point_tmp);
515 if (p_vf_point == NULL) {
516 status = -ENOMEM;
517 goto done;
518 }
519 status = pclk->clk_vf_pointobjs.super.super.objinsert(
520 &pclk->clk_vf_pointobjs.super.super,
521 &p_vf_point->super,
522 *p_vf_point_idx);
523 if (status)
524 goto done;
525
526 p_vf_rail->vf_point_idx_last = (*p_vf_point_idx)++;
527
528done:
529 gk20a_dbg_info("done status %x", status);
530 return status;
531}
532
533static u32 clk_prog_construct_super(struct gk20a *g,
534 struct boardobj **ppboardobj,
535 u16 size, void *pargs)
536{
537 struct clk_prog *pclkprog;
538 u32 status = 0;
539
540 status = boardobj_construct_super(g, ppboardobj,
541 size, pargs);
542 if (status)
543 return -EINVAL;
544
545 pclkprog = (struct clk_prog *)*ppboardobj;
546
547 pclkprog->super.pmudatainit =
548 _clk_prog_pmudatainit_super;
549 return status;
550}
551
552
553static u32 clk_prog_construct_1x(struct gk20a *g,
554 struct boardobj **ppboardobj,
555 u16 size, void *pargs)
556{
557 struct boardobj *ptmpobj = (struct boardobj *)pargs;
558 struct clk_prog_1x *pclkprog;
559 struct clk_prog_1x *ptmpprog =
560 (struct clk_prog_1x *)pargs;
561 u32 status = 0;
562
563 gk20a_dbg_info(" ");
564 ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_PROG_TYPE_1X);
565 status = clk_prog_construct_super(g, ppboardobj, size, pargs);
566 if (status)
567 return -EINVAL;
568
569 pclkprog = (struct clk_prog_1x *)*ppboardobj;
570
571 pclkprog->super.super.pmudatainit =
572 _clk_prog_pmudatainit_1x;
573
574 pclkprog->source = ptmpprog->source;
575 pclkprog->freq_max_mhz = ptmpprog->freq_max_mhz;
576 pclkprog->source_data = ptmpprog->source_data;
577
578 return status;
579}
580
581static u32 clk_prog_construct_1x_master(struct gk20a *g,
582 struct boardobj **ppboardobj,
583 u16 size, void *pargs)
584{
585 struct boardobj *ptmpobj = (struct boardobj *)pargs;
586 struct clk_prog_1x_master *pclkprog;
587 struct clk_prog_1x_master *ptmpprog =
588 (struct clk_prog_1x_master *)pargs;
589 u32 status = 0;
590 u32 vfsize = sizeof(struct ctrl_clk_clk_prog_1x_master_vf_entry) *
591 g->clk_pmu.clk_progobjs.vf_entry_count;
592 u8 railidx;
593
594 gk20a_dbg_info(" type - %x", BOARDOBJ_GET_TYPE(pargs));
595
596 ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_PROG_TYPE_1X_MASTER);
597 status = clk_prog_construct_1x(g, ppboardobj, size, pargs);
598 if (status)
599 return -EINVAL;
600
601 pclkprog = (struct clk_prog_1x_master *)*ppboardobj;
602
603 pclkprog->super.super.super.pmudatainit =
604 _clk_prog_pmudatainit_1x_master;
605
606 pclkprog->vfflatten =
607 vfflatten_prog_1x_master;
608
609 pclkprog->vflookup =
610 vflookup_prog_1x_master;
611
612 pclkprog->getfpoints =
613 getfpoints_prog_1x_master;
614
615 pclkprog->getslaveclk =
616 getslaveclk_prog_1x_master;
617
618 pclkprog->p_vf_entries = (struct ctrl_clk_clk_prog_1x_master_vf_entry *)
619 kzalloc(vfsize, GFP_KERNEL);
620
621 memcpy(pclkprog->p_vf_entries, ptmpprog->p_vf_entries, vfsize);
622
623 pclkprog->b_o_c_o_v_enabled = ptmpprog->b_o_c_o_v_enabled;
624
625 for (railidx = 0;
626 railidx < g->clk_pmu.clk_progobjs.vf_entry_count;
627 railidx++) {
628 pclkprog->p_vf_entries[railidx].vf_point_idx_first =
629 CTRL_CLK_CLK_VF_POINT_IDX_INVALID;
630 pclkprog->p_vf_entries[railidx].vf_point_idx_last =
631 CTRL_CLK_CLK_VF_POINT_IDX_INVALID;
632 }
633
634 return status;
635}
636
637static u32 clk_prog_construct_1x_master_ratio(struct gk20a *g,
638 struct boardobj **ppboardobj,
639 u16 size, void *pargs)
640{
641 struct boardobj *ptmpobj = (struct boardobj *)pargs;
642 struct clk_prog_1x_master_ratio *pclkprog;
643 struct clk_prog_1x_master_ratio *ptmpprog =
644 (struct clk_prog_1x_master_ratio *)pargs;
645 u32 status = 0;
646 u32 slavesize = sizeof(struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry) *
647 g->clk_pmu.clk_progobjs.slave_entry_count;
648
649 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_RATIO)
650 return -EINVAL;
651
652 ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_RATIO);
653 status = clk_prog_construct_1x_master(g, ppboardobj, size, pargs);
654 if (status)
655 return -EINVAL;
656
657 pclkprog = (struct clk_prog_1x_master_ratio *)*ppboardobj;
658
659 pclkprog->super.super.super.super.pmudatainit =
660 _clk_prog_pmudatainit_1x_master_ratio;
661
662 pclkprog->p_slave_entries =
663 (struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry *)
664 kzalloc(slavesize, GFP_KERNEL);
665 if (!pclkprog->p_slave_entries)
666 return -ENOMEM;
667
668 memset(pclkprog->p_slave_entries, CTRL_CLK_CLK_DOMAIN_INDEX_INVALID,
669 slavesize);
670
671 memcpy(pclkprog->p_slave_entries, ptmpprog->p_slave_entries, slavesize);
672
673 return status;
674}
675
676static u32 clk_prog_construct_1x_master_table(struct gk20a *g,
677 struct boardobj **ppboardobj,
678 u16 size, void *pargs)
679{
680 struct boardobj *ptmpobj = (struct boardobj *)pargs;
681 struct clk_prog_1x_master_table *pclkprog;
682 struct clk_prog_1x_master_table *ptmpprog =
683 (struct clk_prog_1x_master_table *)pargs;
684 u32 status = 0;
685 u32 slavesize = sizeof(struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry) *
686 g->clk_pmu.clk_progobjs.slave_entry_count;
687
688 gk20a_dbg_info("type - %x", BOARDOBJ_GET_TYPE(pargs));
689
690 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_TABLE)
691 return -EINVAL;
692
693 ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_TABLE);
694 status = clk_prog_construct_1x_master(g, ppboardobj, size, pargs);
695 if (status)
696 return -EINVAL;
697
698 pclkprog = (struct clk_prog_1x_master_table *)*ppboardobj;
699
700 pclkprog->super.super.super.super.pmudatainit =
701 _clk_prog_pmudatainit_1x_master_table;
702
703 pclkprog->p_slave_entries =
704 (struct ctrl_clk_clk_prog_1x_master_table_slave_entry *)
705 kzalloc(slavesize, GFP_KERNEL);
706 if (!pclkprog->p_slave_entries)
707 return -ENOMEM;
708
709 memset(pclkprog->p_slave_entries, CTRL_CLK_CLK_DOMAIN_INDEX_INVALID,
710 slavesize);
711
712 memcpy(pclkprog->p_slave_entries, ptmpprog->p_slave_entries, slavesize);
713
714 return status;
715}
716
717static struct clk_prog *construct_clk_prog(struct gk20a *g, void *pargs)
718{
719 struct boardobj *board_obj_ptr = NULL;
720 u32 status;
721
722 gk20a_dbg_info(" type - %x", BOARDOBJ_GET_TYPE(pargs));
723 switch (BOARDOBJ_GET_TYPE(pargs)) {
724 case CTRL_CLK_CLK_PROG_TYPE_1X:
725 status = clk_prog_construct_1x(g, &board_obj_ptr,
726 sizeof(struct clk_prog_1x), pargs);
727 break;
728
729 case CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_TABLE:
730 status = clk_prog_construct_1x_master_table(g, &board_obj_ptr,
731 sizeof(struct clk_prog_1x_master_table), pargs);
732 break;
733
734 case CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_RATIO:
735 status = clk_prog_construct_1x_master_ratio(g, &board_obj_ptr,
736 sizeof(struct clk_prog_1x_master_ratio), pargs);
737 break;
738
739 default:
740 return NULL;
741 }
742
743 if (status)
744 return NULL;
745
746 gk20a_dbg_info(" Done");
747
748 return (struct clk_prog *)board_obj_ptr;
749}
750
751static u32 vfflatten_prog_1x_master(struct gk20a *g,
752 struct clk_pmupstate *pclk,
753 struct clk_prog_1x_master *p1xmaster,
754 u8 clk_domain_idx, u16 *pfreqmaxlastmhz)
755{
756 struct ctrl_clk_clk_prog_1x_master_vf_entry *p_vf_rail;
757 union {
758 struct boardobj board_obj;
759 struct clk_vf_point vf_point;
760 struct clk_vf_point_freq freq;
761 struct clk_vf_point_volt volt;
762 } vf_point_data;
763 u32 status = 0;
764 u8 step_count;
765 u8 freq_step_size_mhz = 0;
766 u8 vf_point_idx;
767 u8 vf_rail_idx;
768
769 gk20a_dbg_info("");
770 memset(&vf_point_data, 0x0, sizeof(vf_point_data));
771
772 vf_point_idx = BOARDOBJGRP_NEXT_EMPTY_IDX(
773 &pclk->clk_vf_pointobjs.super.super);
774
775 for (vf_rail_idx = 0;
776 vf_rail_idx < pclk->clk_progobjs.vf_entry_count;
777 vf_rail_idx++) {
778 u32 voltage_min_uv;
779 u32 voltage_step_size_uv;
780 u8 i;
781
782 p_vf_rail = &p1xmaster->p_vf_entries[vf_rail_idx];
783 if (p_vf_rail->vfe_idx == CTRL_BOARDOBJ_IDX_INVALID)
784 continue;
785
786 p_vf_rail->vf_point_idx_first = vf_point_idx;
787
788 vf_point_data.vf_point.vfe_equ_idx = p_vf_rail->vfe_idx;
789 vf_point_data.vf_point.volt_rail_idx = vf_rail_idx;
790
791 step_count = 0;
792
793 switch (p1xmaster->super.source) {
794 case CTRL_CLK_PROG_1X_SOURCE_PLL:
795 freq_step_size_mhz =
796 p1xmaster->super.source_data.pll.freq_step_size_mhz;
797 step_count = (freq_step_size_mhz == 0) ? 0 :
798 (p1xmaster->super.freq_max_mhz - *pfreqmaxlastmhz - 1) /
799 freq_step_size_mhz;
800 /* Intentional fall-through.*/
801
802 case CTRL_CLK_PROG_1X_SOURCE_ONE_SOURCE:
803 vf_point_data.board_obj.type =
804 CTRL_CLK_CLK_VF_POINT_TYPE_FREQ;
805 do {
806 clkvfpointfreqmhzset(g, &vf_point_data.vf_point,
807 p1xmaster->super.freq_max_mhz -
808 step_count * freq_step_size_mhz);
809
810 status = _clk_prog_1x_master_rail_construct_vf_point(g, pclk,
811 p1xmaster, p_vf_rail,
812 &vf_point_data.vf_point, &vf_point_idx);
813 if (status)
814 goto done;
815 } while (step_count-- > 0);
816 break;
817
818 case CTRL_CLK_PROG_1X_SOURCE_FLL:
819 voltage_min_uv = CLK_FLL_LUT_MIN_VOLTAGE_UV(pclk);
820 voltage_step_size_uv = CLK_FLL_LUT_STEP_SIZE_UV(pclk);
821 step_count = CLK_FLL_LUT_VF_NUM_ENTRIES(pclk);
822
823 /* FLL sources use a voltage-based VF_POINT.*/
824 vf_point_data.board_obj.type =
825 CTRL_CLK_CLK_VF_POINT_TYPE_VOLT;
826 for (i = 0; i < step_count; i++) {
827 vf_point_data.volt.source_voltage_uv =
828 voltage_min_uv + i * voltage_step_size_uv;
829
830 status = _clk_prog_1x_master_rail_construct_vf_point(g, pclk,
831 p1xmaster, p_vf_rail,
832 &vf_point_data.vf_point, &vf_point_idx);
833 if (status)
834 goto done;
835 }
836 break;
837 }
838 }
839
840 *pfreqmaxlastmhz = p1xmaster->super.freq_max_mhz;
841
842done:
843 gk20a_dbg_info("done status %x", status);
844 return status;
845}
846
847static u32 vflookup_prog_1x_master
848(
849 struct gk20a *g,
850 struct clk_pmupstate *pclk,
851 struct clk_prog_1x_master *p1xmaster,
852 u8 *slave_clk_domain,
853 u16 *pclkmhz,
854 u32 *pvoltuv,
855 u8 rail
856)
857{
858 int j;
859 struct ctrl_clk_clk_prog_1x_master_vf_entry
860 *pvfentry;
861 struct clk_vf_point *pvfpoint;
862 struct clk_progs *pclkprogobjs;
863 struct clk_prog_1x_master_ratio *p1xmasterratio;
864 u16 clkmhz;
865 u32 voltuv;
866 u8 slaveentrycount;
867 int i;
868 struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry *pslaveents;
869
870 if ((*pclkmhz != 0) && (*pvoltuv != 0))
871 return -EINVAL;
872
873 pclkprogobjs = &(pclk->clk_progobjs);
874
875 slaveentrycount = pclkprogobjs->slave_entry_count;
876
877 if (pclkprogobjs->vf_entry_count >
878 CTRL_CLK_CLK_PROG_1X_MASTER_VF_ENTRY_MAX_ENTRIES)
879 return -EINVAL;
880
881 if (rail >= pclkprogobjs->vf_entry_count)
882 return -EINVAL;
883
884 pvfentry = p1xmaster->p_vf_entries;
885
886 pvfentry = (struct ctrl_clk_clk_prog_1x_master_vf_entry *)(
887 (u8 *)pvfentry +
888 (sizeof(struct ctrl_clk_clk_prog_1x_master_vf_entry) *
889 rail));
890
891 clkmhz = *pclkmhz;
892 voltuv = *pvoltuv;
893
894 /*if domain is slave domain and freq is input
895 then derive master clk */
896 if ((slave_clk_domain != NULL) && (*pclkmhz != 0)) {
897 if (p1xmaster->super.super.super.implements(g,
898 &p1xmaster->super.super.super,
899 CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_RATIO)) {
900
901 p1xmasterratio =
902 (struct clk_prog_1x_master_ratio *)p1xmaster;
903 pslaveents = p1xmasterratio->p_slave_entries;
904 for (i = 0; i < slaveentrycount; i++) {
905 if (pslaveents->clk_dom_idx ==
906 *slave_clk_domain)
907 break;
908 pslaveents++;
909 }
910 if (i == slaveentrycount)
911 return -EINVAL;
912 clkmhz = (clkmhz * 100)/pslaveents->ratio;
913 } else {
914 /* only support ratio for now */
915 return -EINVAL;
916 }
917 }
918
919 /* if both volt and clks are zero simply print*/
920 if ((*pvoltuv == 0) && (*pclkmhz == 0)) {
921 for (j = pvfentry->vf_point_idx_first;
922 j <= pvfentry->vf_point_idx_last; j++) {
923 pvfpoint = CLK_CLK_VF_POINT_GET(pclk, j);
924 gk20a_err(dev_from_gk20a(g), "v %x c %x",
925 clkvfpointvoltageuvget(g, pvfpoint),
926 clkvfpointfreqmhzget(g, pvfpoint));
927 }
928 return -EINVAL;
929 }
930 /* start looking up f for v for v for f */
931 /* looking for volt? */
932 if (*pvoltuv == 0) {
933 pvfpoint = CLK_CLK_VF_POINT_GET(pclk,
934 pvfentry->vf_point_idx_last);
935 /* above range? */
936 if (clkmhz > clkvfpointfreqmhzget(g, pvfpoint))
937 return -EINVAL;
938
939 for (j = pvfentry->vf_point_idx_last;
940 j >= pvfentry->vf_point_idx_first; j--) {
941 pvfpoint = CLK_CLK_VF_POINT_GET(pclk, j);
942 if (clkmhz <= clkvfpointfreqmhzget(g, pvfpoint))
943 voltuv = clkvfpointvoltageuvget(g, pvfpoint);
944 else
945 break;
946 }
947 } else { /* looking for clk? */
948
949 pvfpoint = CLK_CLK_VF_POINT_GET(pclk,
950 pvfentry->vf_point_idx_first);
951 /* below range? */
952 if (voltuv < clkvfpointvoltageuvget(g, pvfpoint))
953 return -EINVAL;
954
955 for (j = pvfentry->vf_point_idx_first;
956 j <= pvfentry->vf_point_idx_last; j++) {
957 pvfpoint = CLK_CLK_VF_POINT_GET(pclk, j);
958 if (voltuv >= clkvfpointvoltageuvget(g, pvfpoint))
959 clkmhz = clkvfpointfreqmhzget(g, pvfpoint);
960 else
961 break;
962 }
963 }
964
965 /*if domain is slave domain and freq was looked up
966 then derive slave clk */
967 if ((slave_clk_domain != NULL) && (*pclkmhz == 0)) {
968 if (p1xmaster->super.super.super.implements(g,
969 &p1xmaster->super.super.super,
970 CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_RATIO)) {
971
972 p1xmasterratio =
973 (struct clk_prog_1x_master_ratio *)p1xmaster;
974 pslaveents = p1xmasterratio->p_slave_entries;
975 for (i = 0; i < slaveentrycount; i++) {
976 if (pslaveents->clk_dom_idx ==
977 *slave_clk_domain)
978 break;
979 pslaveents++;
980 }
981 if (i == slaveentrycount)
982 return -EINVAL;
983 clkmhz = (clkmhz * pslaveents->ratio)/100;
984 } else {
985 /* only support ratio for now */
986 return -EINVAL;
987 }
988 }
989 *pclkmhz = clkmhz;
990 *pvoltuv = voltuv;
991 if ((clkmhz == 0) || (voltuv == 0))
992 return -EINVAL;
993 return 0;
994}
995
996static u32 getfpoints_prog_1x_master
997(
998 struct gk20a *g,
999 struct clk_pmupstate *pclk,
1000 struct clk_prog_1x_master *p1xmaster,
1001 u32 *pfpointscount,
1002 u16 **ppfreqpointsinmhz,
1003 u8 rail
1004)
1005{
1006
1007 struct ctrl_clk_clk_prog_1x_master_vf_entry
1008 *pvfentry;
1009 struct clk_vf_point *pvfpoint;
1010 struct clk_progs *pclkprogobjs;
1011 u8 j;
1012 u32 fpointscount = 0;
1013
1014 if (pfpointscount == NULL)
1015 return -EINVAL;
1016
1017 pclkprogobjs = &(pclk->clk_progobjs);
1018
1019 if (pclkprogobjs->vf_entry_count >
1020 CTRL_CLK_CLK_PROG_1X_MASTER_VF_ENTRY_MAX_ENTRIES)
1021 return -EINVAL;
1022
1023 if (rail >= pclkprogobjs->vf_entry_count)
1024 return -EINVAL;
1025
1026 pvfentry = p1xmaster->p_vf_entries;
1027
1028 pvfentry = (struct ctrl_clk_clk_prog_1x_master_vf_entry *)(
1029 (u8 *)pvfentry +
1030 (sizeof(struct ctrl_clk_clk_prog_1x_master_vf_entry) *
1031 (rail+1)));
1032
1033 fpointscount = pvfentry->vf_point_idx_last -
1034 pvfentry->vf_point_idx_first + 1;
1035
1036 /* if pointer for freq data is NULL simply return count */
1037 if (*ppfreqpointsinmhz == NULL)
1038 goto done;
1039
1040 if (fpointscount > *pfpointscount)
1041 return -ENOMEM;
1042 for (j = pvfentry->vf_point_idx_first;
1043 j <= pvfentry->vf_point_idx_last; j++) {
1044 pvfpoint = CLK_CLK_VF_POINT_GET(pclk, j);
1045 **ppfreqpointsinmhz = clkvfpointfreqmhzget(g, pvfpoint);
1046 (*ppfreqpointsinmhz)++;
1047 }
1048done:
1049 *pfpointscount = fpointscount;
1050 return 0;
1051}
1052
1053static int getslaveclk_prog_1x_master(struct gk20a *g,
1054 struct clk_pmupstate *pclk,
1055 struct clk_prog_1x_master *p1xmaster,
1056 u8 slave_clk_domain,
1057 u16 *pclkmhz,
1058 u16 masterclkmhz
1059)
1060{
1061 struct clk_progs *pclkprogobjs;
1062 struct clk_prog_1x_master_ratio *p1xmasterratio;
1063 u8 slaveentrycount;
1064 u8 i;
1065 struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry *pslaveents;
1066
1067 if (pclkmhz == NULL)
1068 return -EINVAL;
1069
1070 if (masterclkmhz == 0)
1071 return -EINVAL;
1072
1073 *pclkmhz = 0;
1074 pclkprogobjs = &(pclk->clk_progobjs);
1075
1076 slaveentrycount = pclkprogobjs->slave_entry_count;
1077
1078 if (p1xmaster->super.super.super.implements(g,
1079 &p1xmaster->super.super.super,
1080 CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_RATIO)) {
1081 p1xmasterratio =
1082 (struct clk_prog_1x_master_ratio *)p1xmaster;
1083 pslaveents = p1xmasterratio->p_slave_entries;
1084 for (i = 0; i < slaveentrycount; i++) {
1085 if (pslaveents->clk_dom_idx ==
1086 slave_clk_domain)
1087 break;
1088 pslaveents++;
1089 }
1090 if (i == slaveentrycount)
1091 return -EINVAL;
1092 *pclkmhz = (masterclkmhz * pslaveents->ratio)/100;
1093 } else {
1094 /* only support ratio for now */
1095 return -EINVAL;
1096 }
1097 return 0;
1098}
diff --git a/drivers/gpu/nvgpu/clk/clk_prog.h b/drivers/gpu/nvgpu/clk/clk_prog.h
new file mode 100644
index 00000000..60711b4c
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk_prog.h
@@ -0,0 +1,90 @@
1/*
2* Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
3*
4* This program is free software; you can redistribute it and/or modify it
5* under the terms and conditions of the GNU General Public License,
6* version 2, as published by the Free Software Foundation.
7*
8* This program is distributed in the hope it will be useful, but WITHOUT
9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11* more details.
12*/
13
14#ifndef _CLKPROG_H_
15#define _CLKPROG_H_
16#include "ctrl/ctrlclk.h"
17#include "ctrl/ctrlboardobj.h"
18#include "pmuif/gpmuifclk.h"
19#include "boardobj/boardobjgrp_e32.h"
20#include "boardobj/boardobjgrpmask.h"
21
22u32 clk_prog_sw_setup(struct gk20a *g);
23u32 clk_prog_pmu_setup(struct gk20a *g);
24struct clk_prog_1x_master;
25
26typedef u32 vf_flatten(struct gk20a *g, struct clk_pmupstate *pclk,
27 struct clk_prog_1x_master *p1xmaster,
28 u8 clk_domain_idx, u16 *pfreqmaxlastmhz);
29
30typedef u32 vf_lookup(struct gk20a *g, struct clk_pmupstate *pclk,
31 struct clk_prog_1x_master *p1xmaster,
32 u8 *slave_clk_domain_idx, u16 *pclkmhz,
33 u32 *pvoltuv, u8 rail);
34
35typedef int get_slaveclk(struct gk20a *g, struct clk_pmupstate *pclk,
36 struct clk_prog_1x_master *p1xmaster,
37 u8 slave_clk_domain_idx, u16 *pclkmhz,
38 u16 masterclkmhz);
39
40typedef u32 get_fpoints(struct gk20a *g, struct clk_pmupstate *pclk,
41 struct clk_prog_1x_master *p1xmaster,
42 u32 *pfpointscount,
43 u16 **ppfreqpointsinmhz, u8 rail);
44
45
46struct clk_progs {
47 struct boardobjgrp_e255 super;
48 u8 slave_entry_count;
49 u8 vf_entry_count;
50
51};
52
53struct clk_prog {
54 struct boardobj super;
55};
56
57struct clk_prog_1x {
58 struct clk_prog super;
59 u8 source;
60 u16 freq_max_mhz;
61 union ctrl_clk_clk_prog_1x_source_data source_data;
62};
63
64struct clk_prog_1x_master {
65 struct clk_prog_1x super;
66 bool b_o_c_o_v_enabled;
67 struct ctrl_clk_clk_prog_1x_master_vf_entry *p_vf_entries;
68 struct ctrl_clk_clk_delta deltas;
69 union ctrl_clk_clk_prog_1x_master_source_data source_data;
70 vf_flatten *vfflatten;
71 vf_lookup *vflookup;
72 get_fpoints *getfpoints;
73 get_slaveclk *getslaveclk;
74};
75
76struct clk_prog_1x_master_ratio {
77 struct clk_prog_1x_master super;
78 struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry *p_slave_entries;
79};
80
81struct clk_prog_1x_master_table {
82 struct clk_prog_1x_master super;
83 struct ctrl_clk_clk_prog_1x_master_table_slave_entry *p_slave_entries;
84};
85
86#define CLK_CLK_PROG_GET(pclk, idx) \
87 ((struct clk_prog *)BOARDOBJGRP_OBJ_GET_BY_IDX( \
88 &pclk->clk_progobjs.super.super, (u8)(idx)))
89
90#endif
diff --git a/drivers/gpu/nvgpu/clk/clk_vf_point.c b/drivers/gpu/nvgpu/clk/clk_vf_point.c
new file mode 100644
index 00000000..4fde7226
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk_vf_point.c
@@ -0,0 +1,418 @@
1/*
2 * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 */
13
14#include "gk20a/gk20a.h"
15#include "clk.h"
16#include "clk_vf_point.h"
17#include "include/bios.h"
18#include "boardobj/boardobjgrp.h"
19#include "boardobj/boardobjgrp_e32.h"
20#include "pmuif/gpmuifboardobj.h"
21#include "pmuif/gpmuifclk.h"
22#include "gm206/bios_gm206.h"
23#include "ctrl/ctrlclk.h"
24#include "ctrl/ctrlvolt.h"
25#include "gk20a/pmu_gk20a.h"
26
27static u32 _clk_vf_point_pmudatainit_super(struct gk20a *g, struct boardobj
28 *board_obj_ptr, struct nv_pmu_boardobj *ppmudata);
29
30static u32 _clk_vf_points_pmudatainit(struct gk20a *g,
31 struct boardobjgrp *pboardobjgrp,
32 struct nv_pmu_boardobjgrp_super *pboardobjgrppmu)
33{
34 u32 status = 0;
35
36 status = boardobjgrp_pmudatainit_e32(g, pboardobjgrp, pboardobjgrppmu);
37 if (status) {
38 gk20a_err(dev_from_gk20a(g),
39 "error updating pmu boardobjgrp for clk vfpoint 0x%x",
40 status);
41 goto done;
42 }
43
44done:
45 return status;
46}
47
48static u32 _clk_vf_points_pmudata_instget(struct gk20a *g,
49 struct nv_pmu_boardobjgrp *pmuboardobjgrp,
50 struct nv_pmu_boardobj **ppboardobjpmudata,
51 u8 idx)
52{
53 struct nv_pmu_clk_clk_vf_point_boardobj_grp_set *pgrp_set =
54 (struct nv_pmu_clk_clk_vf_point_boardobj_grp_set *)
55 pmuboardobjgrp;
56
57 gk20a_dbg_info("");
58
59 /*check whether pmuboardobjgrp has a valid boardobj in index*/
60 if (idx >= CTRL_BOARDOBJGRP_E255_MAX_OBJECTS)
61 return -EINVAL;
62
63 *ppboardobjpmudata = (struct nv_pmu_boardobj *)
64 &pgrp_set->objects[idx].data.board_obj;
65 gk20a_dbg_info(" Done");
66 return 0;
67}
68
69static u32 _clk_vf_points_pmustatus_instget(struct gk20a *g,
70 void *pboardobjgrppmu,
71 struct nv_pmu_boardobj_query **ppboardobjpmustatus,
72 u8 idx)
73{
74 struct nv_pmu_clk_clk_vf_point_boardobj_grp_get_status *pgrp_get_status =
75 (struct nv_pmu_clk_clk_vf_point_boardobj_grp_get_status *)
76 pboardobjgrppmu;
77
78 /*check whether pmuboardobjgrp has a valid boardobj in index*/
79 if (idx >= CTRL_BOARDOBJGRP_E255_MAX_OBJECTS)
80 return -EINVAL;
81
82 *ppboardobjpmustatus = (struct nv_pmu_boardobj_query *)
83 &pgrp_get_status->objects[idx].data.board_obj;
84 return 0;
85}
86
87u32 clk_vf_point_sw_setup(struct gk20a *g)
88{
89 u32 status;
90 struct boardobjgrp *pboardobjgrp = NULL;
91 struct clk_vf_points *pclkvfpointobjs;
92
93 gk20a_dbg_info("");
94
95 status = boardobjgrpconstruct_e255(&g->clk_pmu.clk_vf_pointobjs.super);
96 if (status) {
97 gk20a_err(dev_from_gk20a(g),
98 "error creating boardobjgrp for clk vfpoint, status - 0x%x",
99 status);
100 goto done;
101 }
102
103 pboardobjgrp = &g->clk_pmu.clk_vf_pointobjs.super.super;
104 pclkvfpointobjs = &(g->clk_pmu.clk_vf_pointobjs);
105
106 BOARDOBJGRP_PMU_CONSTRUCT(pboardobjgrp, CLK, CLK_VF_POINT);
107
108 status = BOARDOBJGRP_PMU_CMD_GRP_SET_CONSTRUCT(g, pboardobjgrp,
109 clk, CLK, clk_vf_point, CLK_VF_POINT);
110 if (status) {
111 gk20a_err(dev_from_gk20a(g),
112 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
113 status);
114 goto done;
115 }
116
117 status = BOARDOBJGRP_PMU_CMD_GRP_GET_STATUS_CONSTRUCT(g,
118 &g->clk_pmu.clk_vf_pointobjs.super.super,
119 clk, CLK, clk_vf_point, CLK_VF_POINT);
120 if (status) {
121 gk20a_err(dev_from_gk20a(g),
122 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
123 status);
124 goto done;
125 }
126
127 pboardobjgrp->pmudatainit = _clk_vf_points_pmudatainit;
128 pboardobjgrp->pmudatainstget = _clk_vf_points_pmudata_instget;
129 pboardobjgrp->pmustatusinstget = _clk_vf_points_pmustatus_instget;
130
131done:
132 gk20a_dbg_info(" done status %x", status);
133 return status;
134}
135
136u32 clk_vf_point_pmu_setup(struct gk20a *g)
137{
138 u32 status;
139 struct boardobjgrp *pboardobjgrp = NULL;
140
141 gk20a_dbg_info("");
142
143 pboardobjgrp = &g->clk_pmu.clk_vf_pointobjs.super.super;
144
145 if (!pboardobjgrp->bconstructed)
146 return -EINVAL;
147
148 status = pboardobjgrp->pmuinithandle(g, pboardobjgrp);
149
150 gk20a_dbg_info("Done");
151 return status;
152}
153
154static u32 clk_vf_point_construct_super(struct gk20a *g,
155 struct boardobj **ppboardobj,
156 u16 size, void *pargs)
157{
158 struct clk_vf_point *pclkvfpoint;
159 struct clk_vf_point *ptmpvfpoint =
160 (struct clk_vf_point *)pargs;
161 u32 status = 0;
162
163 status = boardobj_construct_super(g, ppboardobj,
164 size, pargs);
165 if (status)
166 return -EINVAL;
167
168 pclkvfpoint = (struct clk_vf_point *)*ppboardobj;
169
170 pclkvfpoint->super.pmudatainit =
171 _clk_vf_point_pmudatainit_super;
172
173 pclkvfpoint->vfe_equ_idx = ptmpvfpoint->vfe_equ_idx;
174 pclkvfpoint->volt_rail_idx = ptmpvfpoint->volt_rail_idx;
175
176 return status;
177}
178
179static u32 _clk_vf_point_pmudatainit_volt(struct gk20a *g,
180 struct boardobj *board_obj_ptr,
181 struct nv_pmu_boardobj *ppmudata)
182{
183 u32 status = 0;
184 struct clk_vf_point_volt *pclk_vf_point_volt;
185 struct nv_pmu_clk_clk_vf_point_volt_boardobj_set *pset;
186
187 gk20a_dbg_info("");
188
189 status = _clk_vf_point_pmudatainit_super(g, board_obj_ptr, ppmudata);
190 if (status != 0)
191 return status;
192
193 pclk_vf_point_volt =
194 (struct clk_vf_point_volt *)board_obj_ptr;
195
196 pset = (struct nv_pmu_clk_clk_vf_point_volt_boardobj_set *)
197 ppmudata;
198
199 pset->source_voltage_uv = pclk_vf_point_volt->source_voltage_uv;
200 pset->freq_delta_khz = pclk_vf_point_volt->freq_delta_khz;
201
202 return status;
203}
204
205static u32 _clk_vf_point_pmudatainit_freq(struct gk20a *g,
206 struct boardobj *board_obj_ptr,
207 struct nv_pmu_boardobj *ppmudata)
208{
209 u32 status = 0;
210 struct clk_vf_point_freq *pclk_vf_point_freq;
211 struct nv_pmu_clk_clk_vf_point_freq_boardobj_set *pset;
212
213 gk20a_dbg_info("");
214
215 status = _clk_vf_point_pmudatainit_super(g, board_obj_ptr, ppmudata);
216 if (status != 0)
217 return status;
218
219 pclk_vf_point_freq =
220 (struct clk_vf_point_freq *)board_obj_ptr;
221
222 pset = (struct nv_pmu_clk_clk_vf_point_freq_boardobj_set *)
223 ppmudata;
224
225 pset->freq_mhz =
226 clkvfpointfreqmhzget(g, &pclk_vf_point_freq->super);
227
228 pset->volt_delta_uv = pclk_vf_point_freq->volt_delta_uv;
229
230 return status;
231}
232
233static u32 clk_vf_point_construct_volt(struct gk20a *g,
234 struct boardobj **ppboardobj,
235 u16 size, void *pargs)
236{
237 struct boardobj *ptmpobj = (struct boardobj *)pargs;
238 struct clk_vf_point_volt *pclkvfpoint;
239 struct clk_vf_point_volt *ptmpvfpoint =
240 (struct clk_vf_point_volt *)pargs;
241 u32 status = 0;
242
243 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_CLK_CLK_VF_POINT_TYPE_VOLT)
244 return -EINVAL;
245
246 ptmpobj->type_mask = BIT(CTRL_CLK_CLK_VF_POINT_TYPE_VOLT);
247 status = clk_vf_point_construct_super(g, ppboardobj, size, pargs);
248 if (status)
249 return -EINVAL;
250
251 pclkvfpoint = (struct clk_vf_point_volt *)*ppboardobj;
252
253 pclkvfpoint->super.super.pmudatainit =
254 _clk_vf_point_pmudatainit_volt;
255
256 pclkvfpoint->source_voltage_uv = ptmpvfpoint->source_voltage_uv;
257
258 return status;
259}
260
261static u32 clk_vf_point_construct_freq(struct gk20a *g,
262 struct boardobj **ppboardobj,
263 u16 size, void *pargs)
264{
265 struct boardobj *ptmpobj = (struct boardobj *)pargs;
266 struct clk_vf_point_freq *pclkvfpoint;
267 struct clk_vf_point_freq *ptmpvfpoint =
268 (struct clk_vf_point_freq *)pargs;
269 u32 status = 0;
270
271 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_CLK_CLK_VF_POINT_TYPE_FREQ)
272 return -EINVAL;
273
274 ptmpobj->type_mask = BIT(CTRL_CLK_CLK_VF_POINT_TYPE_FREQ);
275 status = clk_vf_point_construct_super(g, ppboardobj, size, pargs);
276 if (status)
277 return -EINVAL;
278
279 pclkvfpoint = (struct clk_vf_point_freq *)*ppboardobj;
280
281 pclkvfpoint->super.super.pmudatainit =
282 _clk_vf_point_pmudatainit_freq;
283
284 clkvfpointfreqmhzset(g, &pclkvfpoint->super,
285 clkvfpointfreqmhzget(g, &ptmpvfpoint->super));
286
287 return status;
288}
289
290struct clk_vf_point *construct_clk_vf_point(struct gk20a *g, void *pargs)
291{
292 struct boardobj *board_obj_ptr = NULL;
293 u32 status;
294
295 gk20a_dbg_info("");
296 switch (BOARDOBJ_GET_TYPE(pargs)) {
297 case CTRL_CLK_CLK_VF_POINT_TYPE_FREQ:
298 status = clk_vf_point_construct_freq(g, &board_obj_ptr,
299 sizeof(struct clk_vf_point_freq), pargs);
300 break;
301
302 case CTRL_CLK_CLK_VF_POINT_TYPE_VOLT:
303 status = clk_vf_point_construct_volt(g, &board_obj_ptr,
304 sizeof(struct clk_vf_point_volt), pargs);
305 break;
306
307 default:
308 return NULL;
309 }
310
311 if (status)
312 return NULL;
313
314 gk20a_dbg_info(" Done");
315
316 return (struct clk_vf_point *)board_obj_ptr;
317}
318
319static u32 _clk_vf_point_pmudatainit_super(struct gk20a *g,
320 struct boardobj *board_obj_ptr,
321 struct nv_pmu_boardobj *ppmudata)
322{
323 u32 status = 0;
324 struct clk_vf_point *pclk_vf_point;
325 struct nv_pmu_clk_clk_vf_point_boardobj_set *pset;
326
327 gk20a_dbg_info("");
328
329 status = boardobj_pmudatainit_super(g, board_obj_ptr, ppmudata);
330 if (status != 0)
331 return status;
332
333 pclk_vf_point =
334 (struct clk_vf_point *)board_obj_ptr;
335
336 pset = (struct nv_pmu_clk_clk_vf_point_boardobj_set *)
337 ppmudata;
338
339
340 pset->vfe_equ_idx = pclk_vf_point->vfe_equ_idx;
341 pset->volt_rail_idx = pclk_vf_point->volt_rail_idx;
342 return status;
343}
344
345
346static u32 clk_vf_point_update(struct gk20a *g,
347 struct boardobj *board_obj_ptr,
348 struct nv_pmu_boardobj *ppmudata)
349{
350 struct clk_vf_point *pclk_vf_point;
351 struct nv_pmu_clk_clk_vf_point_boardobj_get_status *pstatus;
352
353 gk20a_dbg_info("");
354
355
356 pclk_vf_point =
357 (struct clk_vf_point *)board_obj_ptr;
358
359 pstatus = (struct nv_pmu_clk_clk_vf_point_boardobj_get_status *)
360 ppmudata;
361
362 if (pstatus->super.type != pclk_vf_point->super.type) {
363 gk20a_err(dev_from_gk20a(g),
364 "pmu data and boardobj type not matching");
365 return -EINVAL;
366 }
367 /* now copy VF pair */
368 memcpy(&pclk_vf_point->pair, &pstatus->pair,
369 sizeof(struct ctrl_clk_vf_pair));
370 return 0;
371}
372
373/*get latest vf point data from PMU */
374u32 clk_vf_point_cache(struct gk20a *g)
375{
376
377 struct clk_vf_points *pclk_vf_points;
378 struct boardobjgrp *pboardobjgrp;
379 struct boardobjgrpmask *pboardobjgrpmask;
380 struct nv_pmu_boardobjgrp_super *pboardobjgrppmu;
381 struct boardobj *pboardobj = NULL;
382 struct nv_pmu_boardobj_query *pboardobjpmustatus = NULL;
383 u32 status;
384 u8 index;
385
386 gk20a_dbg_info("");
387 pclk_vf_points = &g->clk_pmu.clk_vf_pointobjs;
388 pboardobjgrp = &pclk_vf_points->super.super;
389 pboardobjgrpmask = &pclk_vf_points->super.mask.super;
390
391 status = pboardobjgrp->pmugetstatus(g, pboardobjgrp, pboardobjgrpmask);
392 if (status) {
393 gk20a_err(dev_from_gk20a(g), "err getting boardobjs from pmu");
394 return status;
395 }
396 pboardobjgrppmu = pboardobjgrp->pmu.getstatus.buf;
397
398 BOARDOBJGRP_FOR_EACH(pboardobjgrp, struct boardobj*, pboardobj, index) {
399 status = pboardobjgrp->pmustatusinstget(g,
400 (struct nv_pmu_boardobjgrp *)pboardobjgrppmu,
401 &pboardobjpmustatus, index);
402 if (status) {
403 gk20a_err(dev_from_gk20a(g),
404 "could not get status object instance");
405 return status;
406 }
407
408 status = clk_vf_point_update(g, pboardobj,
409 (struct nv_pmu_boardobj *)pboardobjpmustatus);
410 if (status) {
411 gk20a_err(dev_from_gk20a(g),
412 "invalid data from pmu at %d", index);
413 return status;
414 }
415 }
416
417 return 0;
418}
diff --git a/drivers/gpu/nvgpu/clk/clk_vf_point.h b/drivers/gpu/nvgpu/clk/clk_vf_point.h
new file mode 100644
index 00000000..15920066
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk_vf_point.h
@@ -0,0 +1,74 @@
1/*
2* Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
3*
4* This program is free software; you can redistribute it and/or modify it
5* under the terms and conditions of the GNU General Public License,
6* version 2, as published by the Free Software Foundation.
7*
8* This program is distributed in the hope it will be useful, but WITHOUT
9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11* more details.
12*/
13
14#ifndef _CLKVFPOINT_H_
15#define _CLKVFPOINT_H_
16#include "ctrl/ctrlclk.h"
17#include "ctrl/ctrlboardobj.h"
18#include "pmuif/gpmuifclk.h"
19#include "boardobj/boardobjgrp_e32.h"
20#include "boardobj/boardobjgrpmask.h"
21
22u32 clk_vf_point_sw_setup(struct gk20a *g);
23u32 clk_vf_point_pmu_setup(struct gk20a *g);
24u32 clk_vf_point_cache(struct gk20a *g);
25
26struct clk_vf_points {
27 struct boardobjgrp_e255 super;
28};
29
30struct clk_vf_point {
31 struct boardobj super;
32 u8 vfe_equ_idx;
33 u8 volt_rail_idx;
34 struct ctrl_clk_vf_pair pair;
35};
36
37struct clk_vf_point_volt {
38 struct clk_vf_point super;
39 u32 source_voltage_uv;
40 int freq_delta_khz;
41};
42
43struct clk_vf_point_freq {
44 struct clk_vf_point super;
45 int volt_delta_uv;
46};
47
48#define CLK_CLK_VF_POINT_GET(pclk, idx) \
49 ((struct clk_vf_point *)BOARDOBJGRP_OBJ_GET_BY_IDX( \
50 &pclk->clk_vf_pointobjs.super.super, (u8)(idx)))
51
52#define clkvfpointpairget(pvfpoint) \
53 (&((pvfpoint)->pair))
54
55#define clkvfpointfreqmhzget(pgpu, pvfpoint) \
56 CTRL_CLK_VF_PAIR_FREQ_MHZ_GET(clkvfpointpairget(pvfpoint))
57
58#define clkvfpointfreqdeltamhzGet(pgpu, pvfPoint) \
59 ((BOARDOBJ_GET_TYPE(pvfpoint) == CTRL_CLK_CLK_VF_POINT_TYPE_VOLT) ? \
60 (((struct clk_vf_point_volt *)(pvfpoint))->freq_delta_khz / 1000) : 0)
61
62#define clkvfpointfreqmhzset(pgpu, pvfpoint, _freqmhz) \
63 CTRL_CLK_VF_PAIR_FREQ_MHZ_SET(clkvfpointpairget(pvfpoint), _freqmhz)
64
65#define clkvfpointvoltageuvset(pgpu, pvfpoint, _voltageuv) \
66 CTRL_CLK_VF_PAIR_VOLTAGE_UV_SET(clkvfpointpairget(pvfpoint), \
67 _voltageuv)
68
69#define clkvfpointvoltageuvget(pgpu, pvfpoint) \
70 CTRL_CLK_VF_PAIR_VOLTAGE_UV_GET(clkvfpointpairget(pvfpoint)) \
71
72struct clk_vf_point *construct_clk_vf_point(struct gk20a *g, void *pargs);
73
74#endif
diff --git a/drivers/gpu/nvgpu/clk/clk_vin.c b/drivers/gpu/nvgpu/clk/clk_vin.c
new file mode 100644
index 00000000..e8e4b753
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk_vin.c
@@ -0,0 +1,466 @@
1/*
2 * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 */
13
14#include "gk20a/gk20a.h"
15#include "clk.h"
16#include "clk_vin.h"
17#include "include/bios.h"
18#include "boardobj/boardobjgrp.h"
19#include "boardobj/boardobjgrp_e32.h"
20#include "pmuif/gpmuifboardobj.h"
21#include "pmuif/gpmuifclk.h"
22#include "gm206/bios_gm206.h"
23#include "ctrl/ctrlvolt.h"
24#include "gk20a/pmu_gk20a.h"
25#include "gp106/hw_fuse_gp106.h"
26
27static u32 devinit_get_vin_device_table(struct gk20a *g,
28 struct avfsvinobjs *pvinobjs);
29
30static struct vin_device *construct_vin_device(struct gk20a *g, void *pargs);
31
32static u32 vin_device_init_pmudata_super(struct gk20a *g,
33 struct boardobj *board_obj_ptr,
34 struct nv_pmu_boardobj *ppmudata);
35
36static u32 read_vin_cal_fuse_rev(struct gk20a *g)
37{
38 return fuse_vin_cal_fuse_rev_v(
39 gk20a_readl(g, fuse_vin_cal_fuse_rev_r()));
40}
41
42static u32 read_vin_cal_slope_intercept_fuse(struct gk20a *g,
43 u32 vin_id, u32 *slope,
44 u32 *intercept)
45{
46 u32 data = 0;
47 u32 interceptdata = 0;
48 u32 slopedata = 0;
49 u32 gpc0data;
50 u32 gpc0slopedata;
51 u32 gpc0interceptdata;
52
53 /* read gpc0 irrespective of vin id */
54 gpc0data = gk20a_readl(g, fuse_vin_cal_gpc0_r());
55 if (gpc0data == 0xFFFFFFFF)
56 return -EINVAL;
57
58 switch (vin_id) {
59 case CTRL_CLK_VIN_ID_GPC0:
60 break;
61
62 case CTRL_CLK_VIN_ID_GPC1:
63 data = gk20a_readl(g, fuse_vin_cal_gpc1_delta_r());
64 break;
65
66 case CTRL_CLK_VIN_ID_GPC2:
67 data = gk20a_readl(g, fuse_vin_cal_gpc2_delta_r());
68 break;
69
70 case CTRL_CLK_VIN_ID_GPC3:
71 data = gk20a_readl(g, fuse_vin_cal_gpc3_delta_r());
72 break;
73
74 case CTRL_CLK_VIN_ID_GPC4:
75 data = gk20a_readl(g, fuse_vin_cal_gpc4_delta_r());
76 break;
77
78 case CTRL_CLK_VIN_ID_GPC5:
79 data = gk20a_readl(g, fuse_vin_cal_gpc5_delta_r());
80 break;
81
82 case CTRL_CLK_VIN_ID_SYS:
83 case CTRL_CLK_VIN_ID_XBAR:
84 case CTRL_CLK_VIN_ID_LTC:
85 data = gk20a_readl(g, fuse_vin_cal_shared_delta_r());
86 break;
87
88 case CTRL_CLK_VIN_ID_SRAM:
89 data = gk20a_readl(g, fuse_vin_cal_sram_delta_r());
90 break;
91
92 default:
93 return -EINVAL;
94 }
95 if (data == 0xFFFFFFFF)
96 return -EINVAL;
97
98 gpc0interceptdata = fuse_vin_cal_gpc0_icpt_data_v(gpc0data) * 1000;
99 gpc0interceptdata = gpc0interceptdata >>
100 fuse_vin_cal_gpc0_icpt_frac_size_v();
101
102 switch (vin_id) {
103 case CTRL_CLK_VIN_ID_GPC0:
104 break;
105
106 case CTRL_CLK_VIN_ID_GPC1:
107 case CTRL_CLK_VIN_ID_GPC2:
108 case CTRL_CLK_VIN_ID_GPC3:
109 case CTRL_CLK_VIN_ID_GPC4:
110 case CTRL_CLK_VIN_ID_GPC5:
111 case CTRL_CLK_VIN_ID_SYS:
112 case CTRL_CLK_VIN_ID_XBAR:
113 case CTRL_CLK_VIN_ID_LTC:
114 interceptdata =
115 (fuse_vin_cal_gpc1_icpt_data_v(data)) * 1000;
116 interceptdata = interceptdata >>
117 fuse_vin_cal_gpc1_icpt_frac_size_v();
118 break;
119
120 case CTRL_CLK_VIN_ID_SRAM:
121 interceptdata =
122 (fuse_vin_cal_sram_icpt_data_v(data)) * 1000;
123 interceptdata = interceptdata >>
124 fuse_vin_cal_sram_icpt_frac_size_v();
125 break;
126
127 default:
128 return -EINVAL;
129 }
130
131 if (data & fuse_vin_cal_gpc1_icpt_sign_f())
132 *intercept = gpc0interceptdata - interceptdata;
133 else
134 *intercept = gpc0interceptdata + interceptdata;
135
136 /* slope */
137 gpc0slopedata = (fuse_vin_cal_gpc0_slope_data_v(gpc0data)) * 1000;
138 gpc0slopedata = gpc0slopedata >>
139 fuse_vin_cal_gpc0_slope_frac_size_v();
140
141 switch (vin_id) {
142 case CTRL_CLK_VIN_ID_GPC0:
143 break;
144
145 case CTRL_CLK_VIN_ID_GPC1:
146 case CTRL_CLK_VIN_ID_GPC2:
147 case CTRL_CLK_VIN_ID_GPC3:
148 case CTRL_CLK_VIN_ID_GPC4:
149 case CTRL_CLK_VIN_ID_GPC5:
150 case CTRL_CLK_VIN_ID_SYS:
151 case CTRL_CLK_VIN_ID_XBAR:
152 case CTRL_CLK_VIN_ID_LTC:
153 case CTRL_CLK_VIN_ID_SRAM:
154 slopedata =
155 (fuse_vin_cal_gpc1_slope_data_v(data)) * 1000;
156 slopedata = slopedata >>
157 fuse_vin_cal_gpc1_slope_frac_size_v();
158 break;
159
160 default:
161 return -EINVAL;
162 }
163
164 if (data & fuse_vin_cal_gpc1_slope_sign_f())
165 *slope = gpc0slopedata - slopedata;
166 else
167 *slope = gpc0slopedata + slopedata;
168 return 0;
169}
170
171static u32 _clk_vin_devgrp_pmudatainit_super(struct gk20a *g,
172 struct boardobjgrp *pboardobjgrp,
173 struct nv_pmu_boardobjgrp_super *pboardobjgrppmu)
174{
175 struct nv_pmu_clk_clk_vin_device_boardobjgrp_set_header *pset =
176 (struct nv_pmu_clk_clk_vin_device_boardobjgrp_set_header *)
177 pboardobjgrppmu;
178 struct avfsvinobjs *pvin_obbj = (struct avfsvinobjs *)pboardobjgrp;
179 u32 status = 0;
180
181 gk20a_dbg_info("");
182
183 status = boardobjgrp_pmudatainit_e32(g, pboardobjgrp, pboardobjgrppmu);
184
185 pset->b_vin_is_disable_allowed = pvin_obbj->vin_is_disable_allowed;
186
187 gk20a_dbg_info(" Done");
188 return status;
189}
190
191static u32 _clk_vin_devgrp_pmudata_instget(struct gk20a *g,
192 struct nv_pmu_boardobjgrp *pmuboardobjgrp,
193 struct nv_pmu_boardobj **ppboardobjpmudata,
194 u8 idx)
195{
196 struct nv_pmu_clk_clk_vin_device_boardobj_grp_set *pgrp_set =
197 (struct nv_pmu_clk_clk_vin_device_boardobj_grp_set *)
198 pmuboardobjgrp;
199
200 gk20a_dbg_info("");
201
202 /*check whether pmuboardobjgrp has a valid boardobj in index*/
203 if (((u32)BIT(idx) &
204 pgrp_set->hdr.data.super.obj_mask.super.data[0]) == 0)
205 return -EINVAL;
206
207 *ppboardobjpmudata = (struct nv_pmu_boardobj *)
208 &pgrp_set->objects[idx].data.board_obj;
209 gk20a_dbg_info(" Done");
210 return 0;
211}
212
213static u32 _clk_vin_devgrp_pmustatus_instget(struct gk20a *g,
214 void *pboardobjgrppmu,
215 struct nv_pmu_boardobj_query **ppboardobjpmustatus,
216 u8 idx)
217{
218 struct nv_pmu_clk_clk_vin_device_boardobj_grp_get_status *pgrp_get_status =
219 (struct nv_pmu_clk_clk_vin_device_boardobj_grp_get_status *)
220 pboardobjgrppmu;
221
222 /*check whether pmuboardobjgrp has a valid boardobj in index*/
223 if (((u32)BIT(idx) &
224 pgrp_get_status->hdr.data.super.obj_mask.super.data[0]) == 0)
225 return -EINVAL;
226
227 *ppboardobjpmustatus = (struct nv_pmu_boardobj_query *)
228 &pgrp_get_status->objects[idx].data.board_obj;
229 return 0;
230}
231
232u32 clk_vin_sw_setup(struct gk20a *g)
233{
234 u32 status;
235 struct boardobjgrp *pboardobjgrp = NULL;
236 u32 slope;
237 u32 intercept;
238 struct vin_device *pvindev;
239 struct avfsvinobjs *pvinobjs;
240 u8 i;
241
242 gk20a_dbg_info("");
243
244 status = boardobjgrpconstruct_e32(&g->clk_pmu.avfs_vinobjs.super);
245 if (status) {
246 gk20a_err(dev_from_gk20a(g),
247 "error creating boardobjgrp for clk vin, statu - 0x%x",
248 status);
249 goto done;
250 }
251
252 pboardobjgrp = &g->clk_pmu.avfs_vinobjs.super.super;
253 pvinobjs = &g->clk_pmu.avfs_vinobjs;
254
255 BOARDOBJGRP_PMU_CONSTRUCT(pboardobjgrp, CLK, VIN_DEVICE);
256
257 status = BOARDOBJGRP_PMU_CMD_GRP_SET_CONSTRUCT(g, pboardobjgrp,
258 clk, CLK, clk_vin_device, CLK_VIN_DEVICE);
259 if (status) {
260 gk20a_err(dev_from_gk20a(g),
261 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
262 status);
263 goto done;
264 }
265
266 pboardobjgrp->pmudatainit = _clk_vin_devgrp_pmudatainit_super;
267 pboardobjgrp->pmudatainstget = _clk_vin_devgrp_pmudata_instget;
268 pboardobjgrp->pmustatusinstget = _clk_vin_devgrp_pmustatus_instget;
269
270 status = devinit_get_vin_device_table(g, &g->clk_pmu.avfs_vinobjs);
271 if (status)
272 goto done;
273
274 /*update vin calibration to fuse */
275 if (pvinobjs->calibration_rev_vbios == read_vin_cal_fuse_rev(g)) {
276 BOARDOBJGRP_FOR_EACH(&(pvinobjs->super.super),
277 struct vin_device *, pvindev, i) {
278 slope = 0;
279 intercept = 0;
280 pvindev = CLK_GET_VIN_DEVICE(pvinobjs, i);
281 status = read_vin_cal_slope_intercept_fuse(g,
282 pvindev->id, &slope, &intercept);
283 if (status) {
284 gk20a_err(dev_from_gk20a(g),
285 "err reading vin cal for id %x", pvindev->id);
286 goto done;
287 }
288 if (slope != 0 && intercept != 0) {
289 pvindev->slope = slope;
290 pvindev->intercept = intercept;
291 }
292 }
293 }
294 status = BOARDOBJGRP_PMU_CMD_GRP_GET_STATUS_CONSTRUCT(g,
295 &g->clk_pmu.avfs_vinobjs.super.super,
296 clk, CLK, clk_vin_device, CLK_VIN_DEVICE);
297 if (status) {
298 gk20a_err(dev_from_gk20a(g),
299 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
300 status);
301 goto done;
302 }
303
304done:
305 gk20a_dbg_info(" done status %x", status);
306 return status;
307}
308
309u32 clk_vin_pmu_setup(struct gk20a *g)
310{
311 u32 status;
312 struct boardobjgrp *pboardobjgrp = NULL;
313
314 gk20a_dbg_info("");
315
316 pboardobjgrp = &g->clk_pmu.avfs_vinobjs.super.super;
317
318 if (!pboardobjgrp->bconstructed)
319 return -EINVAL;
320
321 status = pboardobjgrp->pmuinithandle(g, pboardobjgrp);
322
323 gk20a_dbg_info("Done");
324 return status;
325}
326
327static u32 devinit_get_vin_device_table(struct gk20a *g,
328 struct avfsvinobjs *pvinobjs)
329{
330 u32 status = 0;
331 u8 *vin_table_ptr = NULL;
332 struct vin_descriptor_header_10 vin_desc_table_header = { 0 };
333 struct vin_descriptor_entry_10 vin_desc_table_entry = { 0 };
334 u8 *vin_tbl_entry_ptr = NULL;
335 u32 index = 0;
336 u32 slope, intercept;
337 struct vin_device vin_dev_data;
338 struct vin_device *pvin_dev;
339
340 gk20a_dbg_info("");
341
342 if (g->ops.bios.get_perf_table_ptrs) {
343 vin_table_ptr = (u8 *)g->ops.bios.get_perf_table_ptrs(g,
344 g->bios.clock_token, VIN_TABLE);
345 if (vin_table_ptr == NULL) {
346 status = -1;
347 goto done;
348 }
349 }
350
351 memcpy(&vin_desc_table_header, vin_table_ptr,
352 sizeof(struct vin_descriptor_header_10));
353
354 pvinobjs->calibration_rev_vbios =
355 BIOS_GET_FIELD(vin_desc_table_header.flags0,
356 NV_VIN_DESC_FLAGS0_VIN_CAL_REVISION);
357 pvinobjs->vin_is_disable_allowed =
358 BIOS_GET_FIELD(vin_desc_table_header.flags0,
359 NV_VIN_DESC_FLAGS0_DISABLE_CONTROL);
360
361 /* VIN calibration slope: XX.YYY mV/code => XXYYY uV/code*/
362 slope = ((BIOS_GET_FIELD(vin_desc_table_header.vin_cal,
363 NV_VIN_DESC_VIN_CAL_SLOPE_INTEGER) * 1000)) +
364 ((BIOS_GET_FIELD(vin_desc_table_header.vin_cal,
365 NV_VIN_DESC_VIN_CAL_SLOPE_FRACTION)));
366
367 /* VIN calibration intercept: ZZZ.W mV => ZZZW00 uV */
368 intercept = ((BIOS_GET_FIELD(vin_desc_table_header.vin_cal,
369 NV_VIN_DESC_VIN_CAL_INTERCEPT_INTEGER) * 1000)) +
370 ((BIOS_GET_FIELD(vin_desc_table_header.vin_cal,
371 NV_VIN_DESC_VIN_CAL_INTERCEPT_FRACTION) * 100));
372
373 /* Read table entries*/
374 vin_tbl_entry_ptr = vin_table_ptr + vin_desc_table_header.header_sizee;
375 for (index = 0; index < vin_desc_table_header.entry_count; index++) {
376 u32 vin_id;
377
378 memcpy(&vin_desc_table_entry, vin_tbl_entry_ptr,
379 sizeof(struct vin_descriptor_entry_10));
380
381 if (vin_desc_table_entry.vin_device_type == CTRL_CLK_VIN_TYPE_DISABLED)
382 continue;
383
384 vin_id = vin_desc_table_entry.vin_device_id;
385
386 vin_dev_data.super.type =
387 (u8)vin_desc_table_entry.vin_device_type;
388 vin_dev_data.id = (u8)vin_desc_table_entry.vin_device_id;
389 vin_dev_data.volt_domain_vbios =
390 (u8)vin_desc_table_entry.volt_domain_vbios;
391 vin_dev_data.slope = slope;
392 vin_dev_data.intercept = intercept;
393
394 vin_dev_data.flls_shared_mask = 0;
395
396 pvin_dev = construct_vin_device(g, (void *)&vin_dev_data);
397
398 status = boardobjgrp_objinsert(&pvinobjs->super.super,
399 (struct boardobj *)pvin_dev, index);
400
401 vin_tbl_entry_ptr += vin_desc_table_header.entry_size;
402 }
403
404done:
405 gk20a_dbg_info(" done status %x", status);
406 return status;
407}
408
409static struct vin_device *construct_vin_device(struct gk20a *g, void *pargs)
410{
411 struct boardobj *board_obj_ptr = NULL;
412 struct vin_device *pvin_dev;
413 struct vin_device *board_obj_vin_ptr = NULL;
414 u32 status;
415
416 gk20a_dbg_info("");
417 status = boardobj_construct_super(g, &board_obj_ptr,
418 sizeof(struct vin_device), pargs);
419 if (status)
420 return NULL;
421
422 /*got vin board obj allocated now fill it into boardobj grp*/
423 pvin_dev = (struct vin_device *)pargs;
424 board_obj_vin_ptr = (struct vin_device *)board_obj_ptr;
425 /* override super class interface */
426 board_obj_ptr->pmudatainit = vin_device_init_pmudata_super;
427 board_obj_vin_ptr->id = pvin_dev->id;
428 board_obj_vin_ptr->volt_domain_vbios = pvin_dev->volt_domain_vbios;
429 board_obj_vin_ptr->slope = pvin_dev->slope;
430 board_obj_vin_ptr->intercept = pvin_dev->intercept;
431 board_obj_vin_ptr->flls_shared_mask = pvin_dev->flls_shared_mask;
432 board_obj_vin_ptr->volt_domain = CTRL_VOLT_DOMAIN_LOGIC;
433
434 gk20a_dbg_info(" Done");
435
436 return (struct vin_device *)board_obj_ptr;
437}
438
439static u32 vin_device_init_pmudata_super(struct gk20a *g,
440 struct boardobj *board_obj_ptr,
441 struct nv_pmu_boardobj *ppmudata)
442{
443 u32 status = 0;
444 struct vin_device *pvin_dev;
445 struct nv_pmu_clk_clk_vin_device_boardobj_set *perf_pmu_data;
446
447 gk20a_dbg_info("");
448
449 status = boardobj_pmudatainit_super(g, board_obj_ptr, ppmudata);
450 if (status != 0)
451 return status;
452
453 pvin_dev = (struct vin_device *)board_obj_ptr;
454 perf_pmu_data = (struct nv_pmu_clk_clk_vin_device_boardobj_set *)
455 ppmudata;
456
457 perf_pmu_data->id = pvin_dev->id;
458 perf_pmu_data->intercept = pvin_dev->intercept;
459 perf_pmu_data->volt_domain = pvin_dev->volt_domain;
460 perf_pmu_data->slope = pvin_dev->slope;
461 perf_pmu_data->flls_shared_mask = pvin_dev->flls_shared_mask;
462
463 gk20a_dbg_info(" Done");
464
465 return status;
466}
diff --git a/drivers/gpu/nvgpu/clk/clk_vin.h b/drivers/gpu/nvgpu/clk/clk_vin.h
new file mode 100644
index 00000000..1ffd7971
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk_vin.h
@@ -0,0 +1,56 @@
1/*
2* Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
3*
4* This program is free software; you can redistribute it and/or modify it
5* under the terms and conditions of the GNU General Public License,
6* version 2, as published by the Free Software Foundation.
7*
8* This program is distributed in the hope it will be useful, but WITHOUT
9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11* more details.
12*/
13
14#ifndef _CLKVIN_H_
15#define _CLKVIN_H_
16
17#include "boardobj/boardobj.h"
18#include "boardobj/boardobjgrp.h"
19#include "clk.h"
20
21struct vin_device;
22struct clk_pmupstate;
23
24struct avfsvinobjs {
25 struct boardobjgrp_e32 super;
26 u8 calibration_rev_vbios;
27 u8 calibration_rev_fused;
28 bool vin_is_disable_allowed;
29};
30typedef u32 vin_device_state_load(struct gk20a *g,
31 struct clk_pmupstate *clk, struct vin_device *pdev);
32
33struct vin_device {
34 struct boardobj super;
35 u8 id;
36 u8 volt_domain;
37 u8 volt_domain_vbios;
38 u32 slope;
39 u32 intercept;
40 u32 flls_shared_mask;
41
42 vin_device_state_load *state_load;
43};
44
45/* get vin device object from descriptor table index*/
46#define CLK_GET_VIN_DEVICE(pvinobjs, dev_index) \
47 ((struct vin_device *)BOARDOBJGRP_OBJ_GET_BY_IDX( \
48 ((struct boardobjgrp *)&(pvinobjs->super.super)), (dev_index)))
49
50boardobj_construct construct_vindevice;
51boardobj_pmudatainit vindeviceinit_pmudata_super;
52
53u32 clk_vin_sw_setup(struct gk20a *g);
54u32 clk_vin_pmu_setup(struct gk20a *g);
55
56#endif