summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/common/linux/clk.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/nvgpu/common/linux/clk.c')
-rw-r--r--drivers/gpu/nvgpu/common/linux/clk.c133
1 files changed, 133 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/common/linux/clk.c b/drivers/gpu/nvgpu/common/linux/clk.c
new file mode 100644
index 00000000..775e5661
--- /dev/null
+++ b/drivers/gpu/nvgpu/common/linux/clk.c
@@ -0,0 +1,133 @@
1/*
2 * Linux clock support
3 *
4 * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <linux/clk.h>
20#include <linux/version.h>
21
22#include <soc/tegra/tegra-dvfs.h>
23
24#include "clk.h"
25#include "gk20a/gk20a.h"
26#include "gk20a/platform_gk20a.h"
27
28static unsigned long nvgpu_linux_clk_get_rate(struct gk20a *g, u32 api_domain)
29{
30 struct gk20a_platform *platform = gk20a_get_platform(g->dev);
31 unsigned long ret;
32
33 switch (api_domain) {
34 case CTRL_CLK_DOMAIN_GPCCLK:
35 if (g->clk.tegra_clk)
36 ret = clk_get_rate(g->clk.tegra_clk);
37 else
38 ret = clk_get_rate(platform->clk[0]);
39 break;
40 case CTRL_CLK_DOMAIN_PWRCLK:
41 ret = clk_get_rate(platform->clk[1]);
42 break;
43 default:
44 nvgpu_err(g, "unknown clock: %u", api_domain);
45 ret = 0;
46 break;
47 }
48
49 return ret;
50}
51
52static int nvgpu_linux_clk_set_rate(struct gk20a *g,
53 u32 api_domain, unsigned long rate)
54{
55 struct gk20a_platform *platform = gk20a_get_platform(g->dev);
56 int ret;
57
58 switch (api_domain) {
59 case CTRL_CLK_DOMAIN_GPCCLK:
60 if (g->clk.tegra_clk)
61 ret = clk_set_rate(g->clk.tegra_clk, rate);
62 else
63 ret = clk_set_rate(platform->clk[0], rate);
64 break;
65 case CTRL_CLK_DOMAIN_PWRCLK:
66 ret = clk_set_rate(platform->clk[1], rate);
67 break;
68 default:
69 nvgpu_err(g, "unknown clock: %u", api_domain);
70 ret = -EINVAL;
71 break;
72 }
73
74 return ret;
75}
76
77static unsigned long nvgpu_linux_get_fmax_at_vmin_safe(struct clk_gk20a *clk)
78{
79 /*
80 * On Tegra GPU clock exposed to frequency governor is a shared user on
81 * GPCPLL bus (gbus). The latter can be accessed as GPU clock parent.
82 * Respectively the grandparent is PLL reference clock.
83 */
84 return tegra_dvfs_get_fmax_at_vmin_safe_t(
85 clk_get_parent(clk->tegra_clk));
86}
87
88static u32 nvgpu_linux_get_ref_clock_rate(struct gk20a *g)
89{
90 struct clk *c;
91
92 c = clk_get_sys("gpu_ref", "gpu_ref");
93 if (IS_ERR(c)) {
94 nvgpu_err(g, "failed to get GPCPLL reference clock");
95 return 0;
96 }
97
98 return clk_get_rate(c);
99}
100
101static int nvgpu_linux_predict_mv_at_hz_cur_tfloor(struct clk_gk20a *clk,
102 unsigned long rate)
103{
104 return tegra_dvfs_predict_mv_at_hz_cur_tfloor(
105 clk_get_parent(clk->tegra_clk), rate);
106}
107
108static unsigned long nvgpu_linux_get_maxrate(struct clk_gk20a *clk)
109{
110 return tegra_dvfs_get_maxrate(clk_get_parent(clk->tegra_clk));
111}
112
113static int nvgpu_linux_prepare_enable(struct clk_gk20a *clk)
114{
115 return clk_prepare_enable(clk->tegra_clk);
116}
117
118static void nvgpu_linux_disable_unprepare(struct clk_gk20a *clk)
119{
120 clk_disable_unprepare(clk->tegra_clk);
121}
122
123void nvgpu_linux_init_clk_support(struct gk20a *g)
124{
125 g->ops.clk.get_rate = nvgpu_linux_clk_get_rate;
126 g->ops.clk.set_rate = nvgpu_linux_clk_set_rate;
127 g->ops.clk.get_fmax_at_vmin_safe = nvgpu_linux_get_fmax_at_vmin_safe;
128 g->ops.clk.get_ref_clock_rate = nvgpu_linux_get_ref_clock_rate;
129 g->ops.clk.predict_mv_at_hz_cur_tfloor = nvgpu_linux_predict_mv_at_hz_cur_tfloor;
130 g->ops.clk.get_maxrate = nvgpu_linux_get_maxrate;
131 g->ops.clk.prepare_enable = nvgpu_linux_prepare_enable;
132 g->ops.clk.disable_unprepare = nvgpu_linux_disable_unprepare;
133}