summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/clk/clk_prog.c
diff options
context:
space:
mode:
authorVijayakumar <vsubbu@nvidia.com>2016-08-31 08:10:24 -0400
committerDeepak Nibade <dnibade@nvidia.com>2016-12-27 04:56:50 -0500
commit1b1090512020369df18dbe36336ac5a85d2cd693 (patch)
tree41f3a11dbdff21815545e0e69734c60416783e5e /drivers/gpu/nvgpu/clk/clk_prog.c
parente28ef73ec9baea7df631606298f8c210dc8f31a8 (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/clk_prog.c')
-rw-r--r--drivers/gpu/nvgpu/clk/clk_prog.c153
1 files changed, 153 insertions, 0 deletions
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);
29static u32 devinit_get_clk_prog_table(struct gk20a *g, 29static u32 devinit_get_clk_prog_table(struct gk20a *g,
30 struct clk_progs *pprogobjs); 30 struct clk_progs *pprogobjs);
31static vf_flatten vfflatten_prog_1x_master; 31static vf_flatten vfflatten_prog_1x_master;
32static vf_lookup vflookup_prog_1x_master;
32 33
33static u32 _clk_progs_pmudatainit(struct gk20a *g, 34static 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
839static 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}