diff options
author | Vijayakumar <vsubbu@nvidia.com> | 2016-08-31 08:10:24 -0400 |
---|---|---|
committer | Deepak Nibade <dnibade@nvidia.com> | 2016-12-27 04:56:50 -0500 |
commit | 1b1090512020369df18dbe36336ac5a85d2cd693 (patch) | |
tree | 41f3a11dbdff21815545e0e69734c60416783e5e /drivers/gpu/nvgpu/clk | |
parent | e28ef73ec9baea7df631606298f8c210dc8f31a8 (diff) |
gpu: nvgpu: support to parse VF table
JIRA DNVGPU-123
function was added to retrieve V for F or
F for V for a given clock domain.
Clock domain can be master or slave.
F or V can be intermediate point between two
successive V or F values in VF table.
VF table should be cached before calling this function.
A F value below Fmin will return Vmin.
F > Fmax will return error
A V value above Vmax wil return F max.
A V value below Vmin will return error.
Change-Id: I28b4e8647510c6933e9e1204cfff31d74616e11a
Signed-off-by: Vijayakumar <vsubbu@nvidia.com>
Reviewed-on: http://git-master/r/1211234
(cherry-picked from commit 5b83b03f2454fbec8d49a064ed09b09c92d3e9fa)
Reviewed-on: http://git-master/r/1235054
Reviewed-by: Thomas Fleury <tfleury@nvidia.com>
Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com>
Tested-by: Terje Bergstrom <tbergstrom@nvidia.com>
Diffstat (limited to 'drivers/gpu/nvgpu/clk')
-rw-r--r-- | drivers/gpu/nvgpu/clk/clk.c | 48 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/clk/clk.h | 8 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/clk/clk_domain.c | 125 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/clk/clk_domain.h | 10 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/clk/clk_prog.c | 153 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/clk/clk_prog.h | 6 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/clk/clk_vf_point.h | 7 |
7 files changed, 352 insertions, 5 deletions
diff --git a/drivers/gpu/nvgpu/clk/clk.c b/drivers/gpu/nvgpu/clk/clk.c index 0679efc0..34b344c8 100644 --- a/drivers/gpu/nvgpu/clk/clk.c +++ b/drivers/gpu/nvgpu/clk/clk.c | |||
@@ -188,3 +188,51 @@ u32 clk_pmu_vf_inject(struct gk20a *g) | |||
188 | done: | 188 | done: |
189 | return status; | 189 | return status; |
190 | } | 190 | } |
191 | |||
192 | u32 clk_domain_print_vf_table(struct gk20a *g, u32 clkapidomain) | ||
193 | { | ||
194 | u32 status = -EINVAL; | ||
195 | struct clk_domain *pdomain; | ||
196 | u8 i; | ||
197 | struct clk_pmupstate *pclk = &g->clk_pmu; | ||
198 | u16 clkmhz = 0; | ||
199 | u32 volt = 0; | ||
200 | |||
201 | BOARDOBJGRP_FOR_EACH(&(pclk->clk_domainobjs.super.super), | ||
202 | struct clk_domain *, pdomain, i) { | ||
203 | if (pdomain->api_domain == clkapidomain) { | ||
204 | status = pdomain->clkdomainclkvfsearch(g, pclk, | ||
205 | pdomain, &clkmhz, &volt, | ||
206 | CLK_PROG_VFE_ENTRY_LOGIC); | ||
207 | return status; | ||
208 | } | ||
209 | } | ||
210 | return status; | ||
211 | } | ||
212 | |||
213 | u32 clk_domain_get_f_or_v( | ||
214 | struct gk20a *g, | ||
215 | u32 clkapidomain, | ||
216 | u16 *pclkmhz, | ||
217 | u32 *pvoltuv | ||
218 | ) | ||
219 | { | ||
220 | u32 status = -EINVAL; | ||
221 | struct clk_domain *pdomain; | ||
222 | u8 i; | ||
223 | struct clk_pmupstate *pclk = &g->clk_pmu; | ||
224 | |||
225 | if ((pclkmhz == NULL) || (pvoltuv == NULL)) | ||
226 | return -EINVAL; | ||
227 | |||
228 | BOARDOBJGRP_FOR_EACH(&(pclk->clk_domainobjs.super.super), | ||
229 | struct clk_domain *, pdomain, i) { | ||
230 | if (pdomain->api_domain == clkapidomain) { | ||
231 | status = pdomain->clkdomainclkvfsearch(g, pclk, | ||
232 | pdomain, pclkmhz, pvoltuv, | ||
233 | CLK_PROG_VFE_ENTRY_LOGIC); | ||
234 | return status; | ||
235 | } | ||
236 | } | ||
237 | return status; | ||
238 | } | ||
diff --git a/drivers/gpu/nvgpu/clk/clk.h b/drivers/gpu/nvgpu/clk/clk.h index e24aada2..0d12ba7d 100644 --- a/drivers/gpu/nvgpu/clk/clk.h +++ b/drivers/gpu/nvgpu/clk/clk.h | |||
@@ -84,5 +84,13 @@ struct vbios_clocks_table_1x_hal_clock_entry { | |||
84 | 84 | ||
85 | u32 clk_pmu_vf_inject(struct gk20a *g); | 85 | u32 clk_pmu_vf_inject(struct gk20a *g); |
86 | u32 clk_pmu_vin_load(struct gk20a *g); | 86 | u32 clk_pmu_vin_load(struct gk20a *g); |
87 | u32 clk_domain_print_vf_table(struct gk20a *g, u32 clkapidomain); | ||
88 | u32 clk_domain_get_f_or_v | ||
89 | ( | ||
90 | struct gk20a *g, | ||
91 | u32 clkapidomain, | ||
92 | u16 *pclkmhz, | ||
93 | u32 *pvoltuv | ||
94 | ); | ||
87 | 95 | ||
88 | #endif | 96 | #endif |
diff --git a/drivers/gpu/nvgpu/clk/clk_domain.c b/drivers/gpu/nvgpu/clk/clk_domain.c index 7371946c..c8da851a 100644 --- a/drivers/gpu/nvgpu/clk/clk_domain.c +++ b/drivers/gpu/nvgpu/clk/clk_domain.c | |||
@@ -136,6 +136,8 @@ u32 clk_domain_sw_setup(struct gk20a *g) | |||
136 | struct boardobjgrp *pboardobjgrp = NULL; | 136 | struct boardobjgrp *pboardobjgrp = NULL; |
137 | struct clk_domains *pclkdomainobjs; | 137 | struct clk_domains *pclkdomainobjs; |
138 | struct clk_domain *pdomain; | 138 | struct clk_domain *pdomain; |
139 | struct clk_domain_3x_master *pdomain_master; | ||
140 | struct clk_domain_3x_slave *pdomain_slave; | ||
139 | u8 i; | 141 | u8 i; |
140 | 142 | ||
141 | gk20a_dbg_info(""); | 143 | gk20a_dbg_info(""); |
@@ -186,6 +188,7 @@ u32 clk_domain_sw_setup(struct gk20a *g) | |||
186 | 188 | ||
187 | BOARDOBJGRP_FOR_EACH(&(pclkdomainobjs->super.super), | 189 | BOARDOBJGRP_FOR_EACH(&(pclkdomainobjs->super.super), |
188 | struct clk_domain *, pdomain, i) { | 190 | struct clk_domain *, pdomain, i) { |
191 | pdomain_master = NULL; | ||
189 | if (pdomain->super.implements(g, &pdomain->super, | 192 | if (pdomain->super.implements(g, &pdomain->super, |
190 | CTRL_CLK_CLK_DOMAIN_TYPE_3X_PROG)) { | 193 | CTRL_CLK_CLK_DOMAIN_TYPE_3X_PROG)) { |
191 | status = boardobjgrpmask_bitset( | 194 | status = boardobjgrpmask_bitset( |
@@ -201,6 +204,18 @@ u32 clk_domain_sw_setup(struct gk20a *g) | |||
201 | if (status) | 204 | if (status) |
202 | goto done; | 205 | goto done; |
203 | } | 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 | |||
204 | } | 219 | } |
205 | 220 | ||
206 | done: | 221 | done: |
@@ -407,6 +422,20 @@ static u32 clkdomainclkproglink_not_supported(struct gk20a *g, | |||
407 | return -EINVAL; | 422 | return -EINVAL; |
408 | } | 423 | } |
409 | 424 | ||
425 | static u32 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 | |||
438 | |||
410 | static u32 clk_domain_construct_super(struct gk20a *g, | 439 | static u32 clk_domain_construct_super(struct gk20a *g, |
411 | struct boardobj **ppboardobj, | 440 | struct boardobj **ppboardobj, |
412 | u16 size, void *pargs) | 441 | u16 size, void *pargs) |
@@ -429,6 +458,9 @@ static u32 clk_domain_construct_super(struct gk20a *g, | |||
429 | pdomain->clkdomainclkproglink = | 458 | pdomain->clkdomainclkproglink = |
430 | clkdomainclkproglink_not_supported; | 459 | clkdomainclkproglink_not_supported; |
431 | 460 | ||
461 | pdomain->clkdomainclkvfsearch = | ||
462 | clkdomainvfsearch_stub; | ||
463 | |||
432 | pdomain->api_domain = ptmpdomain->api_domain; | 464 | pdomain->api_domain = ptmpdomain->api_domain; |
433 | pdomain->domain = ptmpdomain->domain; | 465 | pdomain->domain = ptmpdomain->domain; |
434 | pdomain->perf_domain_grp_idx = | 466 | pdomain->perf_domain_grp_idx = |
@@ -508,6 +540,92 @@ static u32 clkdomainclkproglink_3x_prog(struct gk20a *g, | |||
508 | return status; | 540 | return status; |
509 | } | 541 | } |
510 | 542 | ||
543 | static u32 clkdomainvfsearch | ||
544 | ( | ||
545 | struct gk20a *g, | ||
546 | struct clk_pmupstate *pclk, | ||
547 | struct clk_domain *pdomain, | ||
548 | u16 *pclkmhz, | ||
549 | u32 *pvoltuv, | ||
550 | u8 rail | ||
551 | ) | ||
552 | { | ||
553 | u32 status = 0; | ||
554 | struct clk_domain_3x_master *p3xmaster = | ||
555 | (struct clk_domain_3x_master *)pdomain; | ||
556 | struct clk_prog *pprog = NULL; | ||
557 | struct clk_prog_1x_master *pprog1xmaster = NULL; | ||
558 | u8 i; | ||
559 | u8 *pslaveidx = NULL; | ||
560 | u8 slaveidx; | ||
561 | u16 clkmhz; | ||
562 | u32 voltuv; | ||
563 | u16 bestclkmhz; | ||
564 | u32 bestvoltuv; | ||
565 | |||
566 | gk20a_dbg_info(""); | ||
567 | if ((*pclkmhz != 0) && (*pvoltuv != 0)) | ||
568 | return -EINVAL; | ||
569 | |||
570 | bestclkmhz = *pclkmhz; | ||
571 | bestvoltuv = *pvoltuv; | ||
572 | |||
573 | if (pdomain->super.implements(g, &pdomain->super, | ||
574 | CTRL_CLK_CLK_DOMAIN_TYPE_3X_SLAVE)) { | ||
575 | slaveidx = BOARDOBJ_GET_IDX(pdomain); | ||
576 | pslaveidx = &slaveidx; | ||
577 | p3xmaster = (struct clk_domain_3x_master *) | ||
578 | CLK_CLK_DOMAIN_GET(pclk, | ||
579 | ((struct clk_domain_3x_slave *) | ||
580 | pdomain)->master_idx); | ||
581 | } | ||
582 | |||
583 | /* Iterate over the set of CLK_PROGs pointed at by this domain.*/ | ||
584 | for (i = p3xmaster->super.clk_prog_idx_first; | ||
585 | i <= p3xmaster->super.clk_prog_idx_last; | ||
586 | i++) { | ||
587 | clkmhz = *pclkmhz; | ||
588 | voltuv = *pvoltuv; | ||
589 | pprog = CLK_CLK_PROG_GET(pclk, i); | ||
590 | |||
591 | /* MASTER CLK_DOMAINs must point to MASTER CLK_PROGs.*/ | ||
592 | if (!pprog->super.implements(g, &pprog->super, | ||
593 | CTRL_CLK_CLK_PROG_TYPE_1X_MASTER)) { | ||
594 | status = -EINVAL; | ||
595 | goto done; | ||
596 | } | ||
597 | |||
598 | pprog1xmaster = (struct clk_prog_1x_master *)pprog; | ||
599 | status = pprog1xmaster->vflookup(g, pclk, pprog1xmaster, | ||
600 | pslaveidx, &clkmhz, &voltuv, rail); | ||
601 | /* if look up has found the V or F value matching to other | ||
602 | exit */ | ||
603 | if (status == 0) { | ||
604 | if (*pclkmhz == 0) { | ||
605 | bestclkmhz = clkmhz; | ||
606 | } else { | ||
607 | bestvoltuv = voltuv; | ||
608 | break; | ||
609 | } | ||
610 | } | ||
611 | } | ||
612 | /* clk and volt sent as zero to pring vf table */ | ||
613 | if ((*pclkmhz == 0) && (*pvoltuv == 0)) { | ||
614 | status = 0; | ||
615 | goto done; | ||
616 | } | ||
617 | /* atleast one search found a matching value? */ | ||
618 | if ((bestvoltuv != 0) && (bestclkmhz != 0)) { | ||
619 | *pclkmhz = bestclkmhz; | ||
620 | *pvoltuv = bestvoltuv; | ||
621 | status = 0; | ||
622 | goto done; | ||
623 | } | ||
624 | done: | ||
625 | gk20a_dbg_info("done status %x", status); | ||
626 | return status; | ||
627 | } | ||
628 | |||
511 | static u32 _clk_domain_pmudatainit_3x_prog(struct gk20a *g, | 629 | static u32 _clk_domain_pmudatainit_3x_prog(struct gk20a *g, |
512 | struct boardobj *board_obj_ptr, | 630 | struct boardobj *board_obj_ptr, |
513 | struct nv_pmu_boardobj *ppmudata) | 631 | struct nv_pmu_boardobj *ppmudata) |
@@ -568,6 +686,9 @@ static u32 clk_domain_construct_3x_prog(struct gk20a *g, | |||
568 | pdomain->super.super.clkdomainclkproglink = | 686 | pdomain->super.super.clkdomainclkproglink = |
569 | clkdomainclkproglink_3x_prog; | 687 | clkdomainclkproglink_3x_prog; |
570 | 688 | ||
689 | pdomain->super.super.clkdomainclkvfsearch = | ||
690 | clkdomainvfsearch; | ||
691 | |||
571 | pdomain->clk_prog_idx_first = ptmpdomain->clk_prog_idx_first; | 692 | pdomain->clk_prog_idx_first = ptmpdomain->clk_prog_idx_first; |
572 | pdomain->clk_prog_idx_last = ptmpdomain->clk_prog_idx_last; | 693 | pdomain->clk_prog_idx_last = ptmpdomain->clk_prog_idx_last; |
573 | pdomain->noise_unaware_ordering_index = | 694 | pdomain->noise_unaware_ordering_index = |
@@ -707,8 +828,6 @@ static u32 clk_domain_construct_3x_master(struct gk20a *g, | |||
707 | { | 828 | { |
708 | struct boardobj *ptmpobj = (struct boardobj *)pargs; | 829 | struct boardobj *ptmpobj = (struct boardobj *)pargs; |
709 | struct clk_domain_3x_master *pdomain; | 830 | struct clk_domain_3x_master *pdomain; |
710 | struct clk_domain_3x_master *ptmpdomain = | ||
711 | (struct clk_domain_3x_master *)pargs; | ||
712 | u32 status = 0; | 831 | u32 status = 0; |
713 | 832 | ||
714 | if (BOARDOBJ_GET_TYPE(pargs) != CTRL_CLK_CLK_DOMAIN_TYPE_3X_MASTER) | 833 | if (BOARDOBJ_GET_TYPE(pargs) != CTRL_CLK_CLK_DOMAIN_TYPE_3X_MASTER) |
@@ -726,7 +845,7 @@ static u32 clk_domain_construct_3x_master(struct gk20a *g, | |||
726 | pdomain->super.super.super.clkdomainclkproglink = | 845 | pdomain->super.super.super.clkdomainclkproglink = |
727 | clkdomainclkproglink_3x_master; | 846 | clkdomainclkproglink_3x_master; |
728 | 847 | ||
729 | pdomain->slave_idxs_mask = ptmpdomain->slave_idxs_mask; | 848 | pdomain->slave_idxs_mask = 0; |
730 | 849 | ||
731 | return status; | 850 | return status; |
732 | } | 851 | } |
diff --git a/drivers/gpu/nvgpu/clk/clk_domain.h b/drivers/gpu/nvgpu/clk/clk_domain.h index 2670a066..07976a2a 100644 --- a/drivers/gpu/nvgpu/clk/clk_domain.h +++ b/drivers/gpu/nvgpu/clk/clk_domain.h | |||
@@ -26,8 +26,13 @@ struct clk_domain; | |||
26 | /*data and function definition to talk to driver*/ | 26 | /*data and function definition to talk to driver*/ |
27 | u32 clk_domain_sw_setup(struct gk20a *g); | 27 | u32 clk_domain_sw_setup(struct gk20a *g); |
28 | u32 clk_domain_pmu_setup(struct gk20a *g); | 28 | u32 clk_domain_pmu_setup(struct gk20a *g); |
29 | |||
29 | typedef u32 clkproglink(struct gk20a *g, struct clk_pmupstate *pclk, | 30 | typedef u32 clkproglink(struct gk20a *g, struct clk_pmupstate *pclk, |
30 | struct clk_domain *pdomain); | 31 | struct clk_domain *pdomain); |
32 | |||
33 | typedef u32 clkvfsearch(struct gk20a *g, struct clk_pmupstate *pclk, | ||
34 | struct clk_domain *pdomain, u16 *clkmhz, | ||
35 | u32 *voltuv, u8 rail); | ||
31 | struct clk_domains { | 36 | struct clk_domains { |
32 | struct boardobjgrp_e32 super; | 37 | struct boardobjgrp_e32 super; |
33 | u8 n_num_entries; | 38 | u8 n_num_entries; |
@@ -55,6 +60,7 @@ struct clk_domain { | |||
55 | u8 ratio_domain; | 60 | u8 ratio_domain; |
56 | u8 usage; | 61 | u8 usage; |
57 | clkproglink *clkdomainclkproglink; | 62 | clkproglink *clkdomainclkproglink; |
63 | clkvfsearch *clkdomainclkvfsearch; | ||
58 | }; | 64 | }; |
59 | 65 | ||
60 | struct clk_domain_3x { | 66 | struct clk_domain_3x { |
@@ -92,4 +98,8 @@ struct clk_domain_3x_slave { | |||
92 | 98 | ||
93 | u32 clk_domain_clk_prog_link(struct gk20a *g, struct clk_pmupstate *pclk); | 99 | u32 clk_domain_clk_prog_link(struct gk20a *g, struct clk_pmupstate *pclk); |
94 | 100 | ||
101 | #define CLK_CLK_DOMAIN_GET(pclk, idx) \ | ||
102 | ((struct clk_domain *)BOARDOBJGRP_OBJ_GET_BY_IDX( \ | ||
103 | &pclk->clk_domainobjs.super.super, (u8)(idx))) | ||
104 | |||
95 | #endif | 105 | #endif |
diff --git a/drivers/gpu/nvgpu/clk/clk_prog.c b/drivers/gpu/nvgpu/clk/clk_prog.c index 4bf473ac..5e4700a0 100644 --- a/drivers/gpu/nvgpu/clk/clk_prog.c +++ b/drivers/gpu/nvgpu/clk/clk_prog.c | |||
@@ -29,6 +29,7 @@ static struct clk_prog *construct_clk_prog(struct gk20a *g, void *pargs); | |||
29 | static u32 devinit_get_clk_prog_table(struct gk20a *g, | 29 | static u32 devinit_get_clk_prog_table(struct gk20a *g, |
30 | struct clk_progs *pprogobjs); | 30 | struct clk_progs *pprogobjs); |
31 | static vf_flatten vfflatten_prog_1x_master; | 31 | static vf_flatten vfflatten_prog_1x_master; |
32 | static vf_lookup vflookup_prog_1x_master; | ||
32 | 33 | ||
33 | static u32 _clk_progs_pmudatainit(struct gk20a *g, | 34 | static u32 _clk_progs_pmudatainit(struct gk20a *g, |
34 | struct boardobjgrp *pboardobjgrp, | 35 | struct boardobjgrp *pboardobjgrp, |
@@ -603,6 +604,9 @@ static u32 clk_prog_construct_1x_master(struct gk20a *g, | |||
603 | pclkprog->vfflatten = | 604 | pclkprog->vfflatten = |
604 | vfflatten_prog_1x_master; | 605 | vfflatten_prog_1x_master; |
605 | 606 | ||
607 | pclkprog->vflookup = | ||
608 | vflookup_prog_1x_master; | ||
609 | |||
606 | pclkprog->p_vf_entries = (struct ctrl_clk_clk_prog_1x_master_vf_entry *) | 610 | pclkprog->p_vf_entries = (struct ctrl_clk_clk_prog_1x_master_vf_entry *) |
607 | kzalloc(vfsize, GFP_KERNEL); | 611 | kzalloc(vfsize, GFP_KERNEL); |
608 | 612 | ||
@@ -831,3 +835,152 @@ done: | |||
831 | gk20a_dbg_info("done status %x", status); | 835 | gk20a_dbg_info("done status %x", status); |
832 | return status; | 836 | return status; |
833 | } | 837 | } |
838 | |||
839 | static u32 vflookup_prog_1x_master | ||
840 | ( | ||
841 | struct gk20a *g, | ||
842 | struct clk_pmupstate *pclk, | ||
843 | struct clk_prog_1x_master *p1xmaster, | ||
844 | u8 *slave_clk_domain, | ||
845 | u16 *pclkmhz, | ||
846 | u32 *pvoltuv, | ||
847 | u8 rail | ||
848 | ) | ||
849 | { | ||
850 | u8 j; | ||
851 | struct ctrl_clk_clk_prog_1x_master_vf_entry | ||
852 | *pvfentry; | ||
853 | struct clk_vf_point *pvfpoint; | ||
854 | struct clk_progs *pclkprogobjs; | ||
855 | struct clk_prog_1x_master_ratio *p1xmasterratio; | ||
856 | u16 clkmhz; | ||
857 | u32 voltuv; | ||
858 | u8 slaveentrycount; | ||
859 | u8 i; | ||
860 | struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry *pslaveents; | ||
861 | |||
862 | if ((*pclkmhz != 0) && (*pvoltuv != 0)) | ||
863 | return -EINVAL; | ||
864 | |||
865 | pclkprogobjs = &(pclk->clk_progobjs); | ||
866 | |||
867 | slaveentrycount = pclkprogobjs->slave_entry_count; | ||
868 | |||
869 | if (pclkprogobjs->vf_entry_count > | ||
870 | CTRL_CLK_CLK_PROG_1X_MASTER_VF_ENTRY_MAX_ENTRIES) | ||
871 | return -EINVAL; | ||
872 | |||
873 | if (rail >= pclkprogobjs->vf_entry_count) | ||
874 | return -EINVAL; | ||
875 | |||
876 | pvfentry = p1xmaster->p_vf_entries; | ||
877 | |||
878 | pvfentry = (struct ctrl_clk_clk_prog_1x_master_vf_entry *)( | ||
879 | (u8 *)pvfentry + | ||
880 | (sizeof(struct ctrl_clk_clk_prog_1x_master_vf_entry) * | ||
881 | (rail+1))); | ||
882 | |||
883 | clkmhz = *pclkmhz; | ||
884 | voltuv = *pvoltuv; | ||
885 | |||
886 | /*if domain is slave domain and freq is input | ||
887 | then derive master clk */ | ||
888 | if ((slave_clk_domain != NULL) && (*pclkmhz != 0)) { | ||
889 | if (p1xmaster->super.super.super.implements(g, | ||
890 | &p1xmaster->super.super.super, | ||
891 | CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_RATIO)) { | ||
892 | |||
893 | p1xmasterratio = | ||
894 | (struct clk_prog_1x_master_ratio *)p1xmaster; | ||
895 | pslaveents = p1xmasterratio->p_slave_entries; | ||
896 | for (i = 0; i < slaveentrycount; i++) { | ||
897 | if (pslaveents->clk_dom_idx == | ||
898 | *slave_clk_domain) | ||
899 | break; | ||
900 | pslaveents++; | ||
901 | } | ||
902 | if (i == slaveentrycount) | ||
903 | return -EINVAL; | ||
904 | clkmhz = (clkmhz * 100)/pslaveents->ratio; | ||
905 | } else { | ||
906 | /* only support ratio for now */ | ||
907 | return -EINVAL; | ||
908 | } | ||
909 | } | ||
910 | |||
911 | /* if both volt and clks are zero simply print*/ | ||
912 | if ((*pvoltuv == 0) && (*pclkmhz == 0)) { | ||
913 | for (j = pvfentry->vf_point_idx_first; | ||
914 | j <= pvfentry->vf_point_idx_last; j++) { | ||
915 | pvfpoint = CLK_CLK_VF_POINT_GET(pclk, j); | ||
916 | gk20a_err(dev_from_gk20a(g), "v %x c %x", | ||
917 | clkvfpointvoltageuvget(g, pvfpoint), | ||
918 | clkvfpointfreqmhzget(g, pvfpoint)); | ||
919 | } | ||
920 | return -EINVAL; | ||
921 | } | ||
922 | /* start looking up f for v for v for f */ | ||
923 | /* looking for volt? */ | ||
924 | if (*pvoltuv == 0) { | ||
925 | pvfpoint = CLK_CLK_VF_POINT_GET(pclk, | ||
926 | pvfentry->vf_point_idx_last); | ||
927 | /* above range? */ | ||
928 | if (clkmhz > clkvfpointfreqmhzget(g, pvfpoint)) | ||
929 | return -EINVAL; | ||
930 | |||
931 | for (j = pvfentry->vf_point_idx_last; | ||
932 | j >= pvfentry->vf_point_idx_first; j--) { | ||
933 | pvfpoint = CLK_CLK_VF_POINT_GET(pclk, j); | ||
934 | if (clkmhz <= clkvfpointfreqmhzget(g, pvfpoint)) | ||
935 | voltuv = clkvfpointvoltageuvget(g, pvfpoint); | ||
936 | else | ||
937 | break; | ||
938 | } | ||
939 | } else { /* looking for clk? */ | ||
940 | |||
941 | pvfpoint = CLK_CLK_VF_POINT_GET(pclk, | ||
942 | pvfentry->vf_point_idx_first); | ||
943 | /* below range? */ | ||
944 | if (voltuv < clkvfpointvoltageuvget(g, pvfpoint)) | ||
945 | return -EINVAL; | ||
946 | |||
947 | for (j = pvfentry->vf_point_idx_first; | ||
948 | j <= pvfentry->vf_point_idx_last; j++) { | ||
949 | pvfpoint = CLK_CLK_VF_POINT_GET(pclk, j); | ||
950 | if (voltuv >= clkvfpointvoltageuvget(g, pvfpoint)) | ||
951 | clkmhz = clkvfpointfreqmhzget(g, pvfpoint); | ||
952 | else | ||
953 | break; | ||
954 | } | ||
955 | } | ||
956 | |||
957 | /*if domain is slave domain and freq was looked up | ||
958 | then derive slave clk */ | ||
959 | if ((slave_clk_domain != NULL) && (*pclkmhz == 0)) { | ||
960 | if (p1xmaster->super.super.super.implements(g, | ||
961 | &p1xmaster->super.super.super, | ||
962 | CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_RATIO)) { | ||
963 | |||
964 | p1xmasterratio = | ||
965 | (struct clk_prog_1x_master_ratio *)p1xmaster; | ||
966 | pslaveents = p1xmasterratio->p_slave_entries; | ||
967 | for (i = 0; i < slaveentrycount; i++) { | ||
968 | if (pslaveents->clk_dom_idx == | ||
969 | *slave_clk_domain) | ||
970 | break; | ||
971 | pslaveents++; | ||
972 | } | ||
973 | if (i == slaveentrycount) | ||
974 | return -EINVAL; | ||
975 | clkmhz = (clkmhz * pslaveents->ratio)/100; | ||
976 | } else { | ||
977 | /* only support ratio for now */ | ||
978 | return -EINVAL; | ||
979 | } | ||
980 | } | ||
981 | *pclkmhz = clkmhz; | ||
982 | *pvoltuv = voltuv; | ||
983 | if ((clkmhz == 0) || (voltuv == 0)) | ||
984 | return -EINVAL; | ||
985 | return 0; | ||
986 | } | ||
diff --git a/drivers/gpu/nvgpu/clk/clk_prog.h b/drivers/gpu/nvgpu/clk/clk_prog.h index 8718bdd6..979d327d 100644 --- a/drivers/gpu/nvgpu/clk/clk_prog.h +++ b/drivers/gpu/nvgpu/clk/clk_prog.h | |||
@@ -27,6 +27,11 @@ typedef u32 vf_flatten(struct gk20a *g, struct clk_pmupstate *pclk, | |||
27 | struct clk_prog_1x_master *p1xmaster, | 27 | struct clk_prog_1x_master *p1xmaster, |
28 | u8 clk_domain_idx, u16 *pfreqmaxlastmhz); | 28 | u8 clk_domain_idx, u16 *pfreqmaxlastmhz); |
29 | 29 | ||
30 | typedef 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 | |||
30 | struct clk_progs { | 35 | struct clk_progs { |
31 | struct boardobjgrp_e255 super; | 36 | struct boardobjgrp_e255 super; |
32 | u8 slave_entry_count; | 37 | u8 slave_entry_count; |
@@ -52,6 +57,7 @@ struct clk_prog_1x_master { | |||
52 | struct ctrl_clk_clk_delta deltas; | 57 | struct ctrl_clk_clk_delta deltas; |
53 | union ctrl_clk_clk_prog_1x_master_source_data source_data; | 58 | union ctrl_clk_clk_prog_1x_master_source_data source_data; |
54 | vf_flatten *vfflatten; | 59 | vf_flatten *vfflatten; |
60 | vf_lookup *vflookup; | ||
55 | }; | 61 | }; |
56 | 62 | ||
57 | struct clk_prog_1x_master_ratio { | 63 | struct clk_prog_1x_master_ratio { |
diff --git a/drivers/gpu/nvgpu/clk/clk_vf_point.h b/drivers/gpu/nvgpu/clk/clk_vf_point.h index 306bec41..15920066 100644 --- a/drivers/gpu/nvgpu/clk/clk_vf_point.h +++ b/drivers/gpu/nvgpu/clk/clk_vf_point.h | |||
@@ -46,8 +46,8 @@ struct clk_vf_point_freq { | |||
46 | }; | 46 | }; |
47 | 47 | ||
48 | #define CLK_CLK_VF_POINT_GET(pclk, idx) \ | 48 | #define CLK_CLK_VF_POINT_GET(pclk, idx) \ |
49 | ((struct clk_vf_point)BOARDOBJGRP_OBJ_GET_BY_IDX( \ | 49 | ((struct clk_vf_point *)BOARDOBJGRP_OBJ_GET_BY_IDX( \ |
50 | &pclk->vfpoints.super.super, (u8)(idx))) | 50 | &pclk->clk_vf_pointobjs.super.super, (u8)(idx))) |
51 | 51 | ||
52 | #define clkvfpointpairget(pvfpoint) \ | 52 | #define clkvfpointpairget(pvfpoint) \ |
53 | (&((pvfpoint)->pair)) | 53 | (&((pvfpoint)->pair)) |
@@ -66,6 +66,9 @@ struct clk_vf_point_freq { | |||
66 | CTRL_CLK_VF_PAIR_VOLTAGE_UV_SET(clkvfpointpairget(pvfpoint), \ | 66 | CTRL_CLK_VF_PAIR_VOLTAGE_UV_SET(clkvfpointpairget(pvfpoint), \ |
67 | _voltageuv) | 67 | _voltageuv) |
68 | 68 | ||
69 | #define clkvfpointvoltageuvget(pgpu, pvfpoint) \ | ||
70 | CTRL_CLK_VF_PAIR_VOLTAGE_UV_GET(clkvfpointpairget(pvfpoint)) \ | ||
71 | |||
69 | struct clk_vf_point *construct_clk_vf_point(struct gk20a *g, void *pargs); | 72 | struct clk_vf_point *construct_clk_vf_point(struct gk20a *g, void *pargs); |
70 | 73 | ||
71 | #endif | 74 | #endif |