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/clk_prog.c | |
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/clk_prog.c')
-rw-r--r-- | drivers/gpu/nvgpu/clk/clk_prog.c | 153 |
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); | |||
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 | } | ||