gpu: nvgpu: expose linux clock controls via HAL

Expose the linux specific clock implementations via the HAL
interface to allow nvgpu to use the controls globally. This patch
does the following.

1) Implement a new ops interface and a corresponding linux specific
   implementation for allowing nvgpu to iterate through a list of
   available clock frequencies via nvgpu_linux_clk_get_f_points().

2) Implement nvgpu_linux_clk_get_range().

Bug 2061372

Change-Id: I7ce9a999dbdcd9fafcc84301af148545f6ca97a9
Signed-off-by: Debarshi Dutta <ddutta@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/1774280
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
This commit is contained in:
ddutta
2018-09-14 10:48:48 +05:30
committed by mobile promotions
parent feefb7046a
commit 1c7258411d
6 changed files with 158 additions and 0 deletions

View File

@@ -27,6 +27,8 @@
#include "gk20a/gk20a.h"
#define HZ_TO_MHZ(x) ((x) / 1000000)
static unsigned long nvgpu_linux_clk_get_rate(struct gk20a *g, u32 api_domain)
{
struct gk20a_platform *platform = gk20a_get_platform(dev_from_gk20a(g));
@@ -142,6 +144,119 @@ static unsigned long nvgpu_linux_get_maxrate(struct gk20a *g, u32 api_domain)
return ret;
}
/*
* This API is used to return a list of supported frequencies by igpu.
* Set *num_points as 0 to get the size of the freqs list, returned
* by *num_points itself. freqs array must be provided by caller.
* If *num_points is non-zero, then freqs array size must atleast
* equal *num_points.
*/
static int nvgpu_linux_clk_get_f_points(struct gk20a *g,
u32 api_domain, u32 *num_points, u16 *freqs)
{
struct device *dev = dev_from_gk20a(g);
struct gk20a_platform *platform = gk20a_get_platform(dev);
unsigned long *gpu_freq_table;
int ret = 0;
int num_supported_freq = 0;
u32 i;
switch (api_domain) {
case CTRL_CLK_DOMAIN_GPCCLK:
ret = platform->get_clk_freqs(dev, &gpu_freq_table,
&num_supported_freq);
if (ret) {
return ret;
}
if (num_points == NULL) {
return -EINVAL;
}
if (*num_points != 0U) {
if (freqs == NULL || (*num_points > (u32)num_supported_freq)) {
return -EINVAL;
}
}
if (*num_points == 0) {
*num_points = num_supported_freq;
} else {
for (i = 0; i < *num_points; i++) {
freqs[i] = HZ_TO_MHZ(gpu_freq_table[i]);
}
}
break;
default:
nvgpu_err(g, "unknown clock: %u", api_domain);
ret = -EINVAL;
break;
}
return ret;
}
static int nvgpu_clk_get_range(struct gk20a *g, u32 api_domain,
u16 *min_mhz, u16 *max_mhz)
{
struct device *dev = dev_from_gk20a(g);
struct gk20a_platform *platform = gk20a_get_platform(dev);
unsigned long *freqs;
int num_freqs;
int ret;
switch (api_domain) {
case CTRL_CLK_DOMAIN_GPCCLK:
ret = platform->get_clk_freqs(dev, &freqs, &num_freqs);
if (!ret) {
*min_mhz = HZ_TO_MHZ(freqs[0]);
*max_mhz = HZ_TO_MHZ(freqs[num_freqs - 1]);
}
break;
default:
nvgpu_err(g, "unknown clock: %u", api_domain);
ret = -EINVAL;
break;
}
return ret;
}
/* rate_target should be passed in as Hz
rounded_rate is returned in Hz */
static int nvgpu_clk_get_round_rate(struct gk20a *g,
u32 api_domain, unsigned long rate_target,
unsigned long *rounded_rate)
{
struct device *dev = dev_from_gk20a(g);
struct gk20a_platform *platform = gk20a_get_platform(dev);
unsigned long *freqs;
int num_freqs;
int i, ret = 0;
switch (api_domain) {
case CTRL_CLK_DOMAIN_GPCCLK:
ret = platform->get_clk_freqs(dev, &freqs, &num_freqs);
for (i = 0; i < num_freqs; ++i) {
if (freqs[i] >= rate_target) {
*rounded_rate = freqs[i];
return 0;
}
}
*rounded_rate = freqs[num_freqs - 1];
break;
default:
nvgpu_err(g, "unknown clock: %u", api_domain);
ret = -EINVAL;
break;
}
return ret;
}
static int nvgpu_linux_prepare_enable(struct clk_gk20a *clk)
{
return clk_prepare_enable(clk->tegra_clk);
@@ -162,4 +277,7 @@ void nvgpu_linux_init_clk_support(struct gk20a *g)
g->ops.clk.get_maxrate = nvgpu_linux_get_maxrate;
g->ops.clk.prepare_enable = nvgpu_linux_prepare_enable;
g->ops.clk.disable_unprepare = nvgpu_linux_disable_unprepare;
g->ops.clk.clk_domain_get_f_points = nvgpu_linux_clk_get_f_points;
g->ops.clk.get_clk_range = nvgpu_clk_get_range;
g->ops.clk.clk_get_round_rate = nvgpu_clk_get_round_rate;
}