From 1b1090512020369df18dbe36336ac5a85d2cd693 Mon Sep 17 00:00:00 2001 From: Vijayakumar Date: Wed, 31 Aug 2016 17:40:24 +0530 Subject: 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 Reviewed-on: http://git-master/r/1211234 (cherry-picked from commit 5b83b03f2454fbec8d49a064ed09b09c92d3e9fa) Reviewed-on: http://git-master/r/1235054 Reviewed-by: Thomas Fleury Reviewed-by: Terje Bergstrom Tested-by: Terje Bergstrom --- drivers/gpu/nvgpu/clk/clk_prog.c | 153 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) (limited to 'drivers/gpu/nvgpu/clk/clk_prog.c') 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); static u32 devinit_get_clk_prog_table(struct gk20a *g, struct clk_progs *pprogobjs); static vf_flatten vfflatten_prog_1x_master; +static vf_lookup vflookup_prog_1x_master; static u32 _clk_progs_pmudatainit(struct gk20a *g, struct boardobjgrp *pboardobjgrp, @@ -603,6 +604,9 @@ static u32 clk_prog_construct_1x_master(struct gk20a *g, pclkprog->vfflatten = vfflatten_prog_1x_master; + pclkprog->vflookup = + vflookup_prog_1x_master; + pclkprog->p_vf_entries = (struct ctrl_clk_clk_prog_1x_master_vf_entry *) kzalloc(vfsize, GFP_KERNEL); @@ -831,3 +835,152 @@ done: gk20a_dbg_info("done status %x", status); return status; } + +static u32 vflookup_prog_1x_master +( + struct gk20a *g, + struct clk_pmupstate *pclk, + struct clk_prog_1x_master *p1xmaster, + u8 *slave_clk_domain, + u16 *pclkmhz, + u32 *pvoltuv, + u8 rail +) +{ + u8 j; + struct ctrl_clk_clk_prog_1x_master_vf_entry + *pvfentry; + struct clk_vf_point *pvfpoint; + struct clk_progs *pclkprogobjs; + struct clk_prog_1x_master_ratio *p1xmasterratio; + u16 clkmhz; + u32 voltuv; + u8 slaveentrycount; + u8 i; + struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry *pslaveents; + + if ((*pclkmhz != 0) && (*pvoltuv != 0)) + return -EINVAL; + + pclkprogobjs = &(pclk->clk_progobjs); + + slaveentrycount = pclkprogobjs->slave_entry_count; + + if (pclkprogobjs->vf_entry_count > + CTRL_CLK_CLK_PROG_1X_MASTER_VF_ENTRY_MAX_ENTRIES) + return -EINVAL; + + if (rail >= pclkprogobjs->vf_entry_count) + return -EINVAL; + + pvfentry = p1xmaster->p_vf_entries; + + pvfentry = (struct ctrl_clk_clk_prog_1x_master_vf_entry *)( + (u8 *)pvfentry + + (sizeof(struct ctrl_clk_clk_prog_1x_master_vf_entry) * + (rail+1))); + + clkmhz = *pclkmhz; + voltuv = *pvoltuv; + + /*if domain is slave domain and freq is input + then derive master clk */ + if ((slave_clk_domain != NULL) && (*pclkmhz != 0)) { + if (p1xmaster->super.super.super.implements(g, + &p1xmaster->super.super.super, + CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_RATIO)) { + + p1xmasterratio = + (struct clk_prog_1x_master_ratio *)p1xmaster; + pslaveents = p1xmasterratio->p_slave_entries; + for (i = 0; i < slaveentrycount; i++) { + if (pslaveents->clk_dom_idx == + *slave_clk_domain) + break; + pslaveents++; + } + if (i == slaveentrycount) + return -EINVAL; + clkmhz = (clkmhz * 100)/pslaveents->ratio; + } else { + /* only support ratio for now */ + return -EINVAL; + } + } + + /* if both volt and clks are zero simply print*/ + if ((*pvoltuv == 0) && (*pclkmhz == 0)) { + for (j = pvfentry->vf_point_idx_first; + j <= pvfentry->vf_point_idx_last; j++) { + pvfpoint = CLK_CLK_VF_POINT_GET(pclk, j); + gk20a_err(dev_from_gk20a(g), "v %x c %x", + clkvfpointvoltageuvget(g, pvfpoint), + clkvfpointfreqmhzget(g, pvfpoint)); + } + return -EINVAL; + } + /* start looking up f for v for v for f */ + /* looking for volt? */ + if (*pvoltuv == 0) { + pvfpoint = CLK_CLK_VF_POINT_GET(pclk, + pvfentry->vf_point_idx_last); + /* above range? */ + if (clkmhz > clkvfpointfreqmhzget(g, pvfpoint)) + return -EINVAL; + + for (j = pvfentry->vf_point_idx_last; + j >= pvfentry->vf_point_idx_first; j--) { + pvfpoint = CLK_CLK_VF_POINT_GET(pclk, j); + if (clkmhz <= clkvfpointfreqmhzget(g, pvfpoint)) + voltuv = clkvfpointvoltageuvget(g, pvfpoint); + else + break; + } + } else { /* looking for clk? */ + + pvfpoint = CLK_CLK_VF_POINT_GET(pclk, + pvfentry->vf_point_idx_first); + /* below range? */ + if (voltuv < clkvfpointvoltageuvget(g, pvfpoint)) + return -EINVAL; + + for (j = pvfentry->vf_point_idx_first; + j <= pvfentry->vf_point_idx_last; j++) { + pvfpoint = CLK_CLK_VF_POINT_GET(pclk, j); + if (voltuv >= clkvfpointvoltageuvget(g, pvfpoint)) + clkmhz = clkvfpointfreqmhzget(g, pvfpoint); + else + break; + } + } + + /*if domain is slave domain and freq was looked up + then derive slave clk */ + if ((slave_clk_domain != NULL) && (*pclkmhz == 0)) { + if (p1xmaster->super.super.super.implements(g, + &p1xmaster->super.super.super, + CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_RATIO)) { + + p1xmasterratio = + (struct clk_prog_1x_master_ratio *)p1xmaster; + pslaveents = p1xmasterratio->p_slave_entries; + for (i = 0; i < slaveentrycount; i++) { + if (pslaveents->clk_dom_idx == + *slave_clk_domain) + break; + pslaveents++; + } + if (i == slaveentrycount) + return -EINVAL; + clkmhz = (clkmhz * pslaveents->ratio)/100; + } else { + /* only support ratio for now */ + return -EINVAL; + } + } + *pclkmhz = clkmhz; + *pvoltuv = voltuv; + if ((clkmhz == 0) || (voltuv == 0)) + return -EINVAL; + return 0; +} -- cgit v1.2.2