summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/nvgpu/clk/clk.c229
-rw-r--r--drivers/gpu/nvgpu/clk/clk.h24
-rw-r--r--drivers/gpu/nvgpu/clk/clk_domain.c69
-rw-r--r--drivers/gpu/nvgpu/clk/clk_domain.h7
-rw-r--r--drivers/gpu/nvgpu/clk/clk_prog.c55
-rw-r--r--drivers/gpu/nvgpu/clk/clk_prog.h6
-rw-r--r--drivers/gpu/nvgpu/pstate/pstate.c4
7 files changed, 358 insertions, 36 deletions
diff --git a/drivers/gpu/nvgpu/clk/clk.c b/drivers/gpu/nvgpu/clk/clk.c
index 7ee4f283..918cd43c 100644
--- a/drivers/gpu/nvgpu/clk/clk.c
+++ b/drivers/gpu/nvgpu/clk/clk.c
@@ -104,7 +104,7 @@ done:
104 return status; 104 return status;
105} 105}
106 106
107u32 clk_pmu_vf_inject(struct gk20a *g) 107static u32 clk_pmu_vf_inject(struct gk20a *g, struct set_fll_clk *setfllclk)
108{ 108{
109 struct pmu_cmd cmd; 109 struct pmu_cmd cmd;
110 struct pmu_msg msg; 110 struct pmu_msg msg;
@@ -115,35 +115,48 @@ u32 clk_pmu_vf_inject(struct gk20a *g)
115 struct clkrpc_pmucmdhandler_params handler = {0}; 115 struct clkrpc_pmucmdhandler_params handler = {0};
116 struct nv_pmu_clk_vf_change_inject *vfchange; 116 struct nv_pmu_clk_vf_change_inject *vfchange;
117 117
118 if ((setfllclk->gpc2clkmhz == 0) || (setfllclk->xbar2clkmhz == 0) ||
119 (setfllclk->sys2clkmhz == 0) || (setfllclk->voltuv == 0))
120 return -EINVAL;
121
122 if ((setfllclk->target_regime_id_gpc > CTRL_CLK_FLL_REGIME_ID_FR) ||
123 (setfllclk->target_regime_id_sys > CTRL_CLK_FLL_REGIME_ID_FR) ||
124 (setfllclk->target_regime_id_xbar > CTRL_CLK_FLL_REGIME_ID_FR))
125 return -EINVAL;
126
118 rpccall.function = NV_PMU_CLK_RPC_ID_CLK_VF_CHANGE_INJECT; 127 rpccall.function = NV_PMU_CLK_RPC_ID_CLK_VF_CHANGE_INJECT;
119 vfchange = &rpccall.params.clk_vf_change_inject; 128 vfchange = &rpccall.params.clk_vf_change_inject;
120 vfchange->flags = 0; 129 vfchange->flags = 0;
121 vfchange->clk_list.num_domains = 3; 130 vfchange->clk_list.num_domains = 3;
122 vfchange->clk_list.clk_domains[0].clk_domain = CTRL_CLK_DOMAIN_GPC2CLK; 131 vfchange->clk_list.clk_domains[0].clk_domain = CTRL_CLK_DOMAIN_GPC2CLK;
123 vfchange->clk_list.clk_domains[0].clk_freq_khz = 2581 * 1000; 132 vfchange->clk_list.clk_domains[0].clk_freq_khz =
133 setfllclk->gpc2clkmhz * 1000;
124 vfchange->clk_list.clk_domains[0].clk_flags = 0; 134 vfchange->clk_list.clk_domains[0].clk_flags = 0;
125 vfchange->clk_list.clk_domains[0].current_regime_id = 135 vfchange->clk_list.clk_domains[0].current_regime_id =
126 CTRL_CLK_FLL_REGIME_ID_FFR; 136 setfllclk->current_regime_id_gpc;
127 vfchange->clk_list.clk_domains[0].target_regime_id = 137 vfchange->clk_list.clk_domains[0].target_regime_id =
128 CTRL_CLK_FLL_REGIME_ID_FR; 138 setfllclk->target_regime_id_gpc;
129 vfchange->clk_list.clk_domains[1].clk_domain = CTRL_CLK_DOMAIN_XBAR2CLK; 139 vfchange->clk_list.clk_domains[1].clk_domain = CTRL_CLK_DOMAIN_XBAR2CLK;
130 vfchange->clk_list.clk_domains[1].clk_freq_khz = 2505 * 1000; 140 vfchange->clk_list.clk_domains[1].clk_freq_khz =
141 setfllclk->xbar2clkmhz * 1000;
131 vfchange->clk_list.clk_domains[1].clk_flags = 0; 142 vfchange->clk_list.clk_domains[1].clk_flags = 0;
132 vfchange->clk_list.clk_domains[1].current_regime_id = 143 vfchange->clk_list.clk_domains[1].current_regime_id =
133 CTRL_CLK_FLL_REGIME_ID_FFR; 144 setfllclk->current_regime_id_xbar;
134 vfchange->clk_list.clk_domains[1].target_regime_id = 145 vfchange->clk_list.clk_domains[1].target_regime_id =
135 CTRL_CLK_FLL_REGIME_ID_FR; 146 setfllclk->target_regime_id_xbar;
136 vfchange->clk_list.clk_domains[2].clk_domain = CTRL_CLK_DOMAIN_SYS2CLK; 147 vfchange->clk_list.clk_domains[2].clk_domain = CTRL_CLK_DOMAIN_SYS2CLK;
137 vfchange->clk_list.clk_domains[2].clk_freq_khz = 2328 * 1000; 148 vfchange->clk_list.clk_domains[2].clk_freq_khz =
149 setfllclk->sys2clkmhz * 1000;
138 vfchange->clk_list.clk_domains[2].clk_flags = 0; 150 vfchange->clk_list.clk_domains[2].clk_flags = 0;
139 vfchange->clk_list.clk_domains[2].current_regime_id = 151 vfchange->clk_list.clk_domains[2].current_regime_id =
140 CTRL_CLK_FLL_REGIME_ID_FFR; 152 setfllclk->current_regime_id_sys;
141 vfchange->clk_list.clk_domains[2].target_regime_id = 153 vfchange->clk_list.clk_domains[2].target_regime_id =
142 CTRL_CLK_FLL_REGIME_ID_FR; 154 setfllclk->target_regime_id_sys;
143 vfchange->volt_list.num_rails = 1; 155 vfchange->volt_list.num_rails = 1;
144 vfchange->volt_list.rails[0].volt_domain = CTRL_VOLT_DOMAIN_LOGIC; 156 vfchange->volt_list.rails[0].volt_domain = CTRL_VOLT_DOMAIN_LOGIC;
145 vfchange->volt_list.rails[0].voltage_uv = 825000; 157 vfchange->volt_list.rails[0].voltage_uv = setfllclk->voltuv;
146 vfchange->volt_list.rails[0].voltage_min_noise_unaware_uv = 825000; 158 vfchange->volt_list.rails[0].voltage_min_noise_unaware_uv =
159 setfllclk->voltuv;
147 160
148 cmd.hdr.unit_id = PMU_UNIT_CLK; 161 cmd.hdr.unit_id = PMU_UNIT_CLK;
149 cmd.hdr.size = (u32)sizeof(struct nv_pmu_clk_cmd) + 162 cmd.hdr.size = (u32)sizeof(struct nv_pmu_clk_cmd) +
@@ -189,6 +202,198 @@ done:
189 return status; 202 return status;
190} 203}
191 204
205static u32 find_regime_id(struct gk20a *g, u32 domain, u16 clkmhz)
206{
207 struct fll_device *pflldev;
208 u8 j;
209 struct clk_pmupstate *pclk = &g->clk_pmu;
210
211 BOARDOBJGRP_FOR_EACH(&(pclk->avfs_fllobjs.super.super),
212 struct fll_device *, pflldev, j) {
213 if (pflldev->clk_domain == domain) {
214 if (pflldev->regime_desc.fixed_freq_regime_limit_mhz >=
215 clkmhz)
216 return CTRL_CLK_FLL_REGIME_ID_FR;
217 else
218 return CTRL_CLK_FLL_REGIME_ID_FFR;
219 }
220 }
221 return CTRL_CLK_FLL_REGIME_ID_INVALID;
222}
223
224static int set_regime_id(struct gk20a *g, u32 domain, u32 regimeid)
225{
226 struct fll_device *pflldev;
227 u8 j;
228 struct clk_pmupstate *pclk = &g->clk_pmu;
229
230 BOARDOBJGRP_FOR_EACH(&(pclk->avfs_fllobjs.super.super),
231 struct fll_device *, pflldev, j) {
232 if (pflldev->clk_domain == domain) {
233 pflldev->regime_desc.regime_id = regimeid;
234 return 0;
235 }
236 }
237 return -EINVAL;
238}
239
240static int get_regime_id(struct gk20a *g, u32 domain, u32 *regimeid)
241{
242 struct fll_device *pflldev;
243 u8 j;
244 struct clk_pmupstate *pclk = &g->clk_pmu;
245
246 BOARDOBJGRP_FOR_EACH(&(pclk->avfs_fllobjs.super.super),
247 struct fll_device *, pflldev, j) {
248 if (pflldev->clk_domain == domain) {
249 *regimeid = pflldev->regime_desc.regime_id;
250 return 0;
251 }
252 }
253 return -EINVAL;
254}
255
256int clk_program_fllclks(struct gk20a *g, struct change_fll_clk *fllclk)
257{
258 int status = -EINVAL;
259 struct clk_domain *pdomain;
260 u8 i;
261 struct clk_pmupstate *pclk = &g->clk_pmu;
262 u16 clkmhz = 0;
263 struct clk_domain_3x_master *p3xmaster;
264 struct clk_domain_3x_slave *p3xslave;
265 unsigned long slaveidxmask;
266 struct set_fll_clk setfllclk;
267 bool foundxbar2clk = false;
268 bool foundsys2clk = false;
269
270 memset(&setfllclk, 0, sizeof(setfllclk));
271 if (fllclk->api_clk_domain != CTRL_CLK_DOMAIN_GPC2CLK)
272 return -EINVAL;
273 if (fllclk->voltuv == 0)
274 return -EINVAL;
275 if (fllclk->clkmhz == 0)
276 return -EINVAL;
277
278 mutex_lock(&pclk->changeclkmutex);
279
280 setfllclk.voltuv = fllclk->voltuv;
281 setfllclk.gpc2clkmhz = fllclk->clkmhz;
282
283 BOARDOBJGRP_FOR_EACH(&(pclk->clk_domainobjs.super.super),
284 struct clk_domain *, pdomain, i) {
285
286 if (pdomain->api_domain == fllclk->api_clk_domain) {
287
288 if (!pdomain->super.implements(g, &pdomain->super,
289 CTRL_CLK_CLK_DOMAIN_TYPE_3X_MASTER)) {
290 status = -EINVAL;
291 goto done;
292 }
293 p3xmaster = (struct clk_domain_3x_master *)pdomain;
294 slaveidxmask = p3xmaster->slave_idxs_mask;
295 for_each_set_bit(i, &slaveidxmask, 32) {
296 p3xslave = (struct clk_domain_3x_slave *)
297 CLK_CLK_DOMAIN_GET(pclk, i);
298 if ((p3xslave->super.super.super.api_domain !=
299 CTRL_CLK_DOMAIN_XBAR2CLK) &&
300 (p3xslave->super.super.super.api_domain !=
301 CTRL_CLK_DOMAIN_SYS2CLK))
302 continue;
303 clkmhz = 0;
304 status = p3xslave->clkdomainclkgetslaveclk(g,
305 pclk,
306 (struct clk_domain *)p3xslave,
307 &clkmhz,
308 fllclk->clkmhz);
309 if (status) {
310 status = -EINVAL;
311 goto done;
312 }
313 if (p3xslave->super.super.super.api_domain ==
314 CTRL_CLK_DOMAIN_XBAR2CLK) {
315 setfllclk.xbar2clkmhz = clkmhz;
316 foundxbar2clk = true;
317 }
318 if (p3xslave->super.super.super.api_domain ==
319 CTRL_CLK_DOMAIN_SYS2CLK) {
320 setfllclk.sys2clkmhz = clkmhz;
321 foundsys2clk = true;
322 }
323 }
324 }
325 }
326 if (!(foundxbar2clk && foundsys2clk)) {
327 status = -EINVAL;
328 goto done;
329 }
330 /*set regime ids */
331 status = get_regime_id(g, CTRL_CLK_DOMAIN_GPC2CLK,
332 &setfllclk.current_regime_id_gpc);
333 if (status)
334 goto done;
335
336 setfllclk.target_regime_id_gpc = find_regime_id(g,
337 CTRL_CLK_DOMAIN_GPC2CLK, setfllclk.gpc2clkmhz);
338
339 status = get_regime_id(g, CTRL_CLK_DOMAIN_SYS2CLK,
340 &setfllclk.current_regime_id_sys);
341 if (status)
342 goto done;
343
344 setfllclk.target_regime_id_sys = find_regime_id(g,
345 CTRL_CLK_DOMAIN_SYS2CLK, setfllclk.sys2clkmhz);
346
347 status = get_regime_id(g, CTRL_CLK_DOMAIN_XBAR2CLK,
348 &setfllclk.current_regime_id_xbar);
349 if (status)
350 goto done;
351
352 setfllclk.target_regime_id_xbar = find_regime_id(g,
353 CTRL_CLK_DOMAIN_XBAR2CLK, setfllclk.xbar2clkmhz);
354
355 status = clk_pmu_vf_inject(g, &setfllclk);
356
357 if (status)
358 gk20a_err(dev_from_gk20a(g),
359 "vf inject to change clk failed");
360
361 /* save regime ids */
362 status = set_regime_id(g, CTRL_CLK_DOMAIN_XBAR2CLK,
363 setfllclk.target_regime_id_xbar);
364 if (status)
365 goto done;
366
367 status = set_regime_id(g, CTRL_CLK_DOMAIN_GPC2CLK,
368 setfllclk.target_regime_id_gpc);
369 if (status)
370 goto done;
371
372 status = set_regime_id(g, CTRL_CLK_DOMAIN_SYS2CLK,
373 setfllclk.target_regime_id_sys);
374 if (status)
375 goto done;
376done:
377 mutex_unlock(&pclk->changeclkmutex);
378 return status;
379}
380
381int clk_set_boot_fll_clk(struct gk20a *g)
382{
383 int status;
384 struct change_fll_clk bootfllclk;
385
386 mutex_init(&g->clk_pmu.changeclkmutex);
387
388 bootfllclk.api_clk_domain = CTRL_CLK_DOMAIN_GPC2CLK;
389 bootfllclk.clkmhz = 2581;
390 bootfllclk.voltuv = 825000;
391 status = clk_program_fllclks(g, &bootfllclk);
392 if (status)
393 gk20a_err(dev_from_gk20a(g), "attemp to set boot clk failed");
394 return status;
395}
396
192u32 clk_domain_print_vf_table(struct gk20a *g, u32 clkapidomain) 397u32 clk_domain_print_vf_table(struct gk20a *g, u32 clkapidomain)
193{ 398{
194 u32 status = -EINVAL; 399 u32 status = -EINVAL;
diff --git a/drivers/gpu/nvgpu/clk/clk.h b/drivers/gpu/nvgpu/clk/clk.h
index 1f25fa4e..e54af521 100644
--- a/drivers/gpu/nvgpu/clk/clk.h
+++ b/drivers/gpu/nvgpu/clk/clk.h
@@ -35,6 +35,7 @@ struct clk_pmupstate {
35 struct clk_progs clk_progobjs; 35 struct clk_progs clk_progobjs;
36 struct clk_vf_points clk_vf_pointobjs; 36 struct clk_vf_points clk_vf_pointobjs;
37 struct clk_mclk_state clk_mclk; 37 struct clk_mclk_state clk_mclk;
38 struct mutex changeclkmutex;
38}; 39};
39 40
40struct clockentry { 41struct clockentry {
@@ -44,6 +45,25 @@ struct clockentry {
44 u32 api_clk_domain; 45 u32 api_clk_domain;
45}; 46};
46 47
48struct change_fll_clk {
49 u32 api_clk_domain;
50 u16 clkmhz;
51 u32 voltuv;
52};
53
54struct set_fll_clk {
55 u32 voltuv;
56 u16 gpc2clkmhz;
57 u32 current_regime_id_gpc;
58 u32 target_regime_id_gpc;
59 u16 sys2clkmhz;
60 u32 current_regime_id_sys;
61 u32 target_regime_id_sys;
62 u16 xbar2clkmhz;
63 u32 current_regime_id_xbar;
64 u32 target_regime_id_xbar;
65};
66
47#define NV_PERF_HEADER_4X_CLOCKS_DOMAINS_MAX_NUMCLKS 9 67#define NV_PERF_HEADER_4X_CLOCKS_DOMAINS_MAX_NUMCLKS 9
48 68
49struct vbios_clock_domain { 69struct vbios_clock_domain {
@@ -82,7 +102,6 @@ struct vbios_clocks_table_1x_hal_clock_entry {
82#define PERF_CLK_PCIEGENCLK 12 102#define PERF_CLK_PCIEGENCLK 12
83#define PERF_CLK_NUM 13 103#define PERF_CLK_NUM 13
84 104
85u32 clk_pmu_vf_inject(struct gk20a *g);
86u32 clk_pmu_vin_load(struct gk20a *g); 105u32 clk_pmu_vin_load(struct gk20a *g);
87u32 clk_domain_print_vf_table(struct gk20a *g, u32 clkapidomain); 106u32 clk_domain_print_vf_table(struct gk20a *g, u32 clkapidomain);
88u32 clk_domain_get_f_or_v 107u32 clk_domain_get_f_or_v
@@ -98,5 +117,6 @@ u32 clk_domain_get_f_points(
98 u32 *fpointscount, 117 u32 *fpointscount,
99 u16 *freqpointsinmhz 118 u16 *freqpointsinmhz
100); 119);
101 120int clk_set_boot_fll_clk(struct gk20a *g);
121int clk_program_fll_clks(struct gk20a *g, struct change_fll_clk *fllclk);
102#endif 122#endif
diff --git a/drivers/gpu/nvgpu/clk/clk_domain.c b/drivers/gpu/nvgpu/clk/clk_domain.c
index f87530dc..fe3db5d6 100644
--- a/drivers/gpu/nvgpu/clk/clk_domain.c
+++ b/drivers/gpu/nvgpu/clk/clk_domain.c
@@ -422,14 +422,14 @@ static u32 clkdomainclkproglink_not_supported(struct gk20a *g,
422 return -EINVAL; 422 return -EINVAL;
423} 423}
424 424
425static u32 clkdomainvfsearch_stub( 425static int clkdomainvfsearch_stub(
426 struct gk20a *g, 426 struct gk20a *g,
427 struct clk_pmupstate *pclk, 427 struct clk_pmupstate *pclk,
428 struct clk_domain *pdomain, 428 struct clk_domain *pdomain,
429 u16 *clkmhz, 429 u16 *clkmhz,
430 u32 *voltuv, 430 u32 *voltuv,
431 u8 rail 431 u8 rail)
432) 432
433{ 433{
434 gk20a_dbg_info(""); 434 gk20a_dbg_info("");
435 return -EINVAL; 435 return -EINVAL;
@@ -441,8 +441,7 @@ static u32 clkdomaingetfpoints_stub(
441 struct clk_domain *pdomain, 441 struct clk_domain *pdomain,
442 u32 *pfpointscount, 442 u32 *pfpointscount,
443 u16 *pfreqpointsinmhz, 443 u16 *pfreqpointsinmhz,
444 u8 rail 444 u8 rail)
445)
446{ 445{
447 gk20a_dbg_info(""); 446 gk20a_dbg_info("");
448 return -EINVAL; 447 return -EINVAL;
@@ -556,17 +555,47 @@ static u32 clkdomainclkproglink_3x_prog(struct gk20a *g,
556 return status; 555 return status;
557} 556}
558 557
559static u32 clkdomainvfsearch 558static int clkdomaingetslaveclk(struct gk20a *g,
560( 559 struct clk_pmupstate *pclk,
561 struct gk20a *g, 560 struct clk_domain *pdomain,
562 struct clk_pmupstate *pclk, 561 u16 *pclkmhz,
563 struct clk_domain *pdomain, 562 u16 masterclkmhz)
564 u16 *pclkmhz,
565 u32 *pvoltuv,
566 u8 rail
567)
568{ 563{
569 u32 status = 0; 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;
570 struct clk_domain_3x_master *p3xmaster = 599 struct clk_domain_3x_master *p3xmaster =
571 (struct clk_domain_3x_master *)pdomain; 600 (struct clk_domain_3x_master *)pdomain;
572 struct clk_prog *pprog = NULL; 601 struct clk_prog *pprog = NULL;
@@ -580,6 +609,10 @@ static u32 clkdomainvfsearch
580 u32 bestvoltuv; 609 u32 bestvoltuv;
581 610
582 gk20a_dbg_info(""); 611 gk20a_dbg_info("");
612
613 if ((pclkmhz == NULL) || (pvoltuv == NULL))
614 return -EINVAL;
615
583 if ((*pclkmhz != 0) && (*pvoltuv != 0)) 616 if ((*pclkmhz != 0) && (*pvoltuv != 0))
584 return -EINVAL; 617 return -EINVAL;
585 618
@@ -595,7 +628,6 @@ static u32 clkdomainvfsearch
595 ((struct clk_domain_3x_slave *) 628 ((struct clk_domain_3x_slave *)
596 pdomain)->master_idx); 629 pdomain)->master_idx);
597 } 630 }
598
599 /* Iterate over the set of CLK_PROGs pointed at by this domain.*/ 631 /* Iterate over the set of CLK_PROGs pointed at by this domain.*/
600 for (i = p3xmaster->super.clk_prog_idx_first; 632 for (i = p3xmaster->super.clk_prog_idx_first;
601 i <= p3xmaster->super.clk_prog_idx_last; 633 i <= p3xmaster->super.clk_prog_idx_last;
@@ -625,7 +657,7 @@ static u32 clkdomainvfsearch
625 } 657 }
626 } 658 }
627 } 659 }
628 /* clk and volt sent as zero to pring vf table */ 660 /* clk and volt sent as zero to print vf table */
629 if ((*pclkmhz == 0) && (*pvoltuv == 0)) { 661 if ((*pclkmhz == 0) && (*pvoltuv == 0)) {
630 status = 0; 662 status = 0;
631 goto done; 663 goto done;
@@ -836,6 +868,9 @@ static u32 clk_domain_construct_3x_slave(struct gk20a *g,
836 868
837 pdomain->master_idx = ptmpdomain->master_idx; 869 pdomain->master_idx = ptmpdomain->master_idx;
838 870
871 pdomain->clkdomainclkgetslaveclk =
872 clkdomaingetslaveclk;
873
839 return status; 874 return status;
840} 875}
841 876
diff --git a/drivers/gpu/nvgpu/clk/clk_domain.h b/drivers/gpu/nvgpu/clk/clk_domain.h
index eeb7c256..443e1c4c 100644
--- a/drivers/gpu/nvgpu/clk/clk_domain.h
+++ b/drivers/gpu/nvgpu/clk/clk_domain.h
@@ -30,10 +30,14 @@ u32 clk_domain_pmu_setup(struct gk20a *g);
30typedef u32 clkproglink(struct gk20a *g, struct clk_pmupstate *pclk, 30typedef u32 clkproglink(struct gk20a *g, struct clk_pmupstate *pclk,
31 struct clk_domain *pdomain); 31 struct clk_domain *pdomain);
32 32
33typedef u32 clkvfsearch(struct gk20a *g, struct clk_pmupstate *pclk, 33typedef int clkvfsearch(struct gk20a *g, struct clk_pmupstate *pclk,
34 struct clk_domain *pdomain, u16 *clkmhz, 34 struct clk_domain *pdomain, u16 *clkmhz,
35 u32 *voltuv, u8 rail); 35 u32 *voltuv, u8 rail);
36 36
37typedef int clkgetslaveclk(struct gk20a *g, struct clk_pmupstate *pclk,
38 struct clk_domain *pdomain, u16 *clkmhz,
39 u16 masterclkmhz);
40
37typedef u32 clkgetfpoints(struct gk20a *g, struct clk_pmupstate *pclk, 41typedef u32 clkgetfpoints(struct gk20a *g, struct clk_pmupstate *pclk,
38 struct clk_domain *pdomain, u32 *pfpointscount, 42 struct clk_domain *pdomain, u32 *pfpointscount,
39 u16 *pfreqpointsinmhz, u8 rail); 43 u16 *pfreqpointsinmhz, u8 rail);
@@ -100,6 +104,7 @@ struct clk_domain_3x_master {
100struct clk_domain_3x_slave { 104struct clk_domain_3x_slave {
101 struct clk_domain_3x_prog super; 105 struct clk_domain_3x_prog super;
102 u8 master_idx; 106 u8 master_idx;
107 clkgetslaveclk *clkdomainclkgetslaveclk;
103}; 108};
104 109
105u32 clk_domain_clk_prog_link(struct gk20a *g, struct clk_pmupstate *pclk); 110u32 clk_domain_clk_prog_link(struct gk20a *g, struct clk_pmupstate *pclk);
diff --git a/drivers/gpu/nvgpu/clk/clk_prog.c b/drivers/gpu/nvgpu/clk/clk_prog.c
index cb9a0e8d..9fdd8b25 100644
--- a/drivers/gpu/nvgpu/clk/clk_prog.c
+++ b/drivers/gpu/nvgpu/clk/clk_prog.c
@@ -31,6 +31,7 @@ static u32 devinit_get_clk_prog_table(struct gk20a *g,
31static vf_flatten vfflatten_prog_1x_master; 31static vf_flatten vfflatten_prog_1x_master;
32static vf_lookup vflookup_prog_1x_master; 32static vf_lookup vflookup_prog_1x_master;
33static get_fpoints getfpoints_prog_1x_master; 33static get_fpoints getfpoints_prog_1x_master;
34static get_slaveclk getslaveclk_prog_1x_master;
34 35
35static u32 _clk_progs_pmudatainit(struct gk20a *g, 36static u32 _clk_progs_pmudatainit(struct gk20a *g,
36 struct boardobjgrp *pboardobjgrp, 37 struct boardobjgrp *pboardobjgrp,
@@ -611,6 +612,9 @@ static u32 clk_prog_construct_1x_master(struct gk20a *g,
611 pclkprog->getfpoints = 612 pclkprog->getfpoints =
612 getfpoints_prog_1x_master; 613 getfpoints_prog_1x_master;
613 614
615 pclkprog->getslaveclk =
616 getslaveclk_prog_1x_master;
617
614 pclkprog->p_vf_entries = (struct ctrl_clk_clk_prog_1x_master_vf_entry *) 618 pclkprog->p_vf_entries = (struct ctrl_clk_clk_prog_1x_master_vf_entry *)
615 kzalloc(vfsize, GFP_KERNEL); 619 kzalloc(vfsize, GFP_KERNEL);
616 620
@@ -851,7 +855,7 @@ static u32 vflookup_prog_1x_master
851 u8 rail 855 u8 rail
852) 856)
853{ 857{
854 u8 j; 858 int j;
855 struct ctrl_clk_clk_prog_1x_master_vf_entry 859 struct ctrl_clk_clk_prog_1x_master_vf_entry
856 *pvfentry; 860 *pvfentry;
857 struct clk_vf_point *pvfpoint; 861 struct clk_vf_point *pvfpoint;
@@ -860,7 +864,7 @@ static u32 vflookup_prog_1x_master
860 u16 clkmhz; 864 u16 clkmhz;
861 u32 voltuv; 865 u32 voltuv;
862 u8 slaveentrycount; 866 u8 slaveentrycount;
863 u8 i; 867 int i;
864 struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry *pslaveents; 868 struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry *pslaveents;
865 869
866 if ((*pclkmhz != 0) && (*pvoltuv != 0)) 870 if ((*pclkmhz != 0) && (*pvoltuv != 0))
@@ -1045,3 +1049,50 @@ done:
1045 *pfpointscount = fpointscount; 1049 *pfpointscount = fpointscount;
1046 return 0; 1050 return 0;
1047} 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
index be92b3fc..60711b4c 100644
--- a/drivers/gpu/nvgpu/clk/clk_prog.h
+++ b/drivers/gpu/nvgpu/clk/clk_prog.h
@@ -32,6 +32,11 @@ typedef u32 vf_lookup(struct gk20a *g, struct clk_pmupstate *pclk,
32 u8 *slave_clk_domain_idx, u16 *pclkmhz, 32 u8 *slave_clk_domain_idx, u16 *pclkmhz,
33 u32 *pvoltuv, u8 rail); 33 u32 *pvoltuv, u8 rail);
34 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
35typedef u32 get_fpoints(struct gk20a *g, struct clk_pmupstate *pclk, 40typedef u32 get_fpoints(struct gk20a *g, struct clk_pmupstate *pclk,
36 struct clk_prog_1x_master *p1xmaster, 41 struct clk_prog_1x_master *p1xmaster,
37 u32 *pfpointscount, 42 u32 *pfpointscount,
@@ -65,6 +70,7 @@ struct clk_prog_1x_master {
65 vf_flatten *vfflatten; 70 vf_flatten *vfflatten;
66 vf_lookup *vflookup; 71 vf_lookup *vflookup;
67 get_fpoints *getfpoints; 72 get_fpoints *getfpoints;
73 get_slaveclk *getslaveclk;
68}; 74};
69 75
70struct clk_prog_1x_master_ratio { 76struct clk_prog_1x_master_ratio {
diff --git a/drivers/gpu/nvgpu/pstate/pstate.c b/drivers/gpu/nvgpu/pstate/pstate.c
index 94ff5010..d6173275 100644
--- a/drivers/gpu/nvgpu/pstate/pstate.c
+++ b/drivers/gpu/nvgpu/pstate/pstate.c
@@ -95,11 +95,11 @@ int gk20a_init_pstate_pmu_support(struct gk20a *g)
95 if (err) 95 if (err)
96 return err; 96 return err;
97 97
98 err = clk_pmu_vf_inject(g); 98 err = clk_vf_point_cache(g);
99 if (err) 99 if (err)
100 return err; 100 return err;
101 101
102 err = clk_vf_point_cache(g); 102 err = clk_set_boot_fll_clk(g);
103 return err; 103 return err;
104} 104}
105 105