summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVijayakumar <vsubbu@nvidia.com>2016-11-04 07:17:51 -0400
committerDeepak Nibade <dnibade@nvidia.com>2016-12-27 04:56:52 -0500
commit8cc67f60644a117eec868fc1b11da9a60d2915d7 (patch)
tree5b32619b84feed4d9925c519ffe1dac5fd7b3775
parent30bf630bded30376a929345247b134b60db1c9f5 (diff)
gpu: nvgpu: add clock freq controller support
JIRA DNVGPU-170 1) Add clock frequency controller VBIOS structure definitions 2) Parse VBIOS tables and build boardobj structures for clock frequency controller. 3) send clock frequency controller data structures to PMU 4) implement public function to send load/unload command to pmu to enable/disable clock frequency controller support Change-Id: I2f37f6a94f342b6fcc71bb802e6e440a0a454486 Signed-off-by: Vijayakumar <vsubbu@nvidia.com> Reviewed-on: http://git-master/r/1248209 Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com> Tested-by: Terje Bergstrom <tbergstrom@nvidia.com> (cherry picked from commit ed3e27933f21e10b3d7a5257f1b751526945bd07) Reviewed-on: http://git-master/r/1270897 GVS: Gerrit_Virtual_Submit
-rw-r--r--drivers/gpu/nvgpu/Makefile.nvgpu-t18x1
-rw-r--r--drivers/gpu/nvgpu/clk/clk.c72
-rw-r--r--drivers/gpu/nvgpu/clk/clk.h4
-rw-r--r--drivers/gpu/nvgpu/clk/clk_freq_controller.c454
-rw-r--r--drivers/gpu/nvgpu/clk/clk_freq_controller.h74
-rw-r--r--drivers/gpu/nvgpu/include/bios.h83
-rw-r--r--drivers/gpu/nvgpu/pstate/pstate.c9
7 files changed, 696 insertions, 1 deletions
diff --git a/drivers/gpu/nvgpu/Makefile.nvgpu-t18x b/drivers/gpu/nvgpu/Makefile.nvgpu-t18x
index a096a438..9e08e2c6 100644
--- a/drivers/gpu/nvgpu/Makefile.nvgpu-t18x
+++ b/drivers/gpu/nvgpu/Makefile.nvgpu-t18x
@@ -39,6 +39,7 @@ nvgpu-y += \
39 $(nvgpu-t18x)/clk/clk_prog.o \ 39 $(nvgpu-t18x)/clk/clk_prog.o \
40 $(nvgpu-t18x)/clk/clk_vf_point.o \ 40 $(nvgpu-t18x)/clk/clk_vf_point.o \
41 $(nvgpu-t18x)/clk/clk_arb.o \ 41 $(nvgpu-t18x)/clk/clk_arb.o \
42 $(nvgpu-t18x)/clk/clk_freq_controller.o \
42 $(nvgpu-t18x)/perf/vfe_var.o \ 43 $(nvgpu-t18x)/perf/vfe_var.o \
43 $(nvgpu-t18x)/perf/vfe_equ.o \ 44 $(nvgpu-t18x)/perf/vfe_equ.o \
44 $(nvgpu-t18x)/perf/perf.o \ 45 $(nvgpu-t18x)/perf/perf.o \
diff --git a/drivers/gpu/nvgpu/clk/clk.c b/drivers/gpu/nvgpu/clk/clk.c
index 07c80e22..dffbefec 100644
--- a/drivers/gpu/nvgpu/clk/clk.c
+++ b/drivers/gpu/nvgpu/clk/clk.c
@@ -47,6 +47,78 @@ static void clkrpc_pmucmdhandler(struct gk20a *g, struct pmu_msg *msg,
47 phandlerparams->success = 1; 47 phandlerparams->success = 1;
48} 48}
49 49
50int clk_pmu_freq_controller_load(struct gk20a *g, bool bload)
51{
52 struct pmu_cmd cmd;
53 struct pmu_msg msg;
54 struct pmu_payload payload = { {0} };
55 u32 status;
56 u32 seqdesc;
57 struct nv_pmu_clk_rpc rpccall = {0};
58 struct clkrpc_pmucmdhandler_params handler = {0};
59 struct nv_pmu_clk_load *clkload;
60 struct clk_freq_controllers *pclk_freq_controllers;
61 struct ctrl_boardobjgrp_mask_e32 *load_mask;
62
63 pclk_freq_controllers = &g->clk_pmu.clk_freq_controllers;
64 rpccall.function = NV_PMU_CLK_RPC_ID_LOAD;
65 clkload = &rpccall.params.clk_load;
66 clkload->feature = NV_NV_PMU_CLK_LOAD_FEATURE_FREQ_CONTROLLER;
67 clkload->action_mask = bload ?
68 NV_NV_PMU_CLK_LOAD_ACTION_MASK_FREQ_CONTROLLER_CALLBACK_YES :
69 NV_NV_PMU_CLK_LOAD_ACTION_MASK_FREQ_CONTROLLER_CALLBACK_NO;
70
71 load_mask = &rpccall.params.clk_load.payload.freq_controllers.load_mask;
72
73 status = boardobjgrpmask_export(
74 &pclk_freq_controllers->freq_ctrl_load_mask.super,
75 pclk_freq_controllers->freq_ctrl_load_mask.super.bitcount,
76 &load_mask->super);
77
78 cmd.hdr.unit_id = PMU_UNIT_CLK;
79 cmd.hdr.size = (u32)sizeof(struct nv_pmu_clk_cmd) +
80 (u32)sizeof(struct pmu_hdr);
81
82 cmd.cmd.clk.cmd_type = NV_PMU_CLK_CMD_ID_RPC;
83 msg.hdr.size = sizeof(struct pmu_msg);
84
85 payload.in.buf = (u8 *)&rpccall;
86 payload.in.size = (u32)sizeof(struct nv_pmu_clk_rpc);
87 payload.in.fb_size = PMU_CMD_SUBMIT_PAYLOAD_PARAMS_FB_SIZE_UNUSED;
88 payload.in.offset = NV_PMU_CLK_CMD_RPC_ALLOC_OFFSET;
89
90 payload.out.buf = (u8 *)&rpccall;
91 payload.out.size = (u32)sizeof(struct nv_pmu_clk_rpc);
92 payload.out.fb_size = PMU_CMD_SUBMIT_PAYLOAD_PARAMS_FB_SIZE_UNUSED;
93 payload.out.offset = NV_PMU_CLK_MSG_RPC_ALLOC_OFFSET;
94
95 handler.prpccall = &rpccall;
96 handler.success = 0;
97 status = gk20a_pmu_cmd_post(g, &cmd, NULL, &payload,
98 PMU_COMMAND_QUEUE_LPQ,
99 clkrpc_pmucmdhandler, (void *)&handler,
100 &seqdesc, ~0);
101
102 if (status) {
103 gk20a_err(dev_from_gk20a(g),
104 "unable to post clk RPC cmd %x",
105 cmd.cmd.clk.cmd_type);
106 goto done;
107 }
108
109 pmu_wait_message_cond(&g->pmu,
110 gk20a_get_gr_idle_timeout(g),
111 &handler.success, 1);
112
113 if (handler.success == 0) {
114 gk20a_err(dev_from_gk20a(g), "rpc call to load freq cntlr cal failed");
115 status = -EINVAL;
116 }
117
118done:
119 return status;
120}
121
50u32 clk_pmu_vin_load(struct gk20a *g) 122u32 clk_pmu_vin_load(struct gk20a *g)
51{ 123{
52 struct pmu_cmd cmd; 124 struct pmu_cmd cmd;
diff --git a/drivers/gpu/nvgpu/clk/clk.h b/drivers/gpu/nvgpu/clk/clk.h
index 42cb9f7d..b173a09e 100644
--- a/drivers/gpu/nvgpu/clk/clk.h
+++ b/drivers/gpu/nvgpu/clk/clk.h
@@ -21,6 +21,7 @@
21#include "clk_prog.h" 21#include "clk_prog.h"
22#include "clk_vf_point.h" 22#include "clk_vf_point.h"
23#include "clk_mclk.h" 23#include "clk_mclk.h"
24#include "clk_freq_controller.h"
24#include "gk20a/gk20a.h" 25#include "gk20a/gk20a.h"
25 26
26#define NV_PERF_DOMAIN_4X_CLOCK_DOMAIN_SKIP 0x10 27#define NV_PERF_DOMAIN_4X_CLOCK_DOMAIN_SKIP 0x10
@@ -35,6 +36,7 @@ struct clk_pmupstate {
35 struct clk_progs clk_progobjs; 36 struct clk_progs clk_progobjs;
36 struct clk_vf_points clk_vf_pointobjs; 37 struct clk_vf_points clk_vf_pointobjs;
37 struct clk_mclk_state clk_mclk; 38 struct clk_mclk_state clk_mclk;
39 struct clk_freq_controllers clk_freq_controllers;
38}; 40};
39 41
40struct clockentry { 42struct clockentry {
@@ -114,5 +116,5 @@ u32 clk_domain_get_f_points(
114); 116);
115int clk_get_fll_clks(struct gk20a *g, struct set_fll_clk *fllclk); 117int clk_get_fll_clks(struct gk20a *g, struct set_fll_clk *fllclk);
116int clk_set_fll_clks(struct gk20a *g, struct set_fll_clk *fllclk); 118int clk_set_fll_clks(struct gk20a *g, struct set_fll_clk *fllclk);
117 119int clk_pmu_freq_controller_load(struct gk20a *g, bool bload);
118#endif 120#endif
diff --git a/drivers/gpu/nvgpu/clk/clk_freq_controller.c b/drivers/gpu/nvgpu/clk/clk_freq_controller.c
new file mode 100644
index 00000000..17f79168
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk_freq_controller.c
@@ -0,0 +1,454 @@
1/*
2 * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 */
13
14#include "gk20a/gk20a.h"
15#include "clk.h"
16#include "clk_fll.h"
17#include "clk_domain.h"
18#include "clk_freq_controller.h"
19#include "include/bios.h"
20#include "boardobj/boardobjgrp.h"
21#include "boardobj/boardobjgrp_e32.h"
22#include "pmuif/gpmuifboardobj.h"
23#include "pmuif/gpmuifclk.h"
24#include "gm206/bios_gm206.h"
25#include "ctrl/ctrlclk.h"
26#include "ctrl/ctrlvolt.h"
27#include "gk20a/pmu_gk20a.h"
28
29static u32 clk_freq_controller_pmudatainit_super(struct gk20a *g,
30 struct boardobj *board_obj_ptr,
31 struct nv_pmu_boardobj *ppmudata)
32{
33 struct nv_pmu_clk_clk_freq_controller_boardobj_set *pfreq_cntlr_set;
34 struct clk_freq_controller *pfreq_cntlr;
35 u32 status = 0;
36
37 status = boardobj_pmudatainit_super(g, board_obj_ptr, ppmudata);
38 if (status)
39 return status;
40
41 pfreq_cntlr_set =
42 (struct nv_pmu_clk_clk_freq_controller_boardobj_set *)ppmudata;
43 pfreq_cntlr = (struct clk_freq_controller *)board_obj_ptr;
44
45 pfreq_cntlr_set->controller_id = pfreq_cntlr->controller_id;
46 pfreq_cntlr_set->clk_domain = pfreq_cntlr->clk_domain;
47 pfreq_cntlr_set->parts_freq_mode = pfreq_cntlr->parts_freq_mode;
48 pfreq_cntlr_set->bdisable = pfreq_cntlr->bdisable;
49 pfreq_cntlr_set->freq_cap_noise_unaware_vmin_above =
50 pfreq_cntlr->freq_cap_noise_unaware_vmin_above;
51 pfreq_cntlr_set->freq_cap_noise_unaware_vmin_below =
52 pfreq_cntlr->freq_cap_noise_unaware_vmin_below;
53 pfreq_cntlr_set->freq_hyst_pos_mhz = pfreq_cntlr->freq_hyst_pos_mhz;
54 pfreq_cntlr_set->freq_hyst_neg_mhz = pfreq_cntlr->freq_hyst_neg_mhz;
55
56 return status;
57}
58
59static u32 clk_freq_controller_pmudatainit_pi(struct gk20a *g,
60 struct boardobj *board_obj_ptr,
61 struct nv_pmu_boardobj *ppmudata)
62{
63 struct nv_pmu_clk_clk_freq_controller_pi_boardobj_set
64 *pfreq_cntlr_pi_set;
65 struct clk_freq_controller_pi *pfreq_cntlr_pi;
66 u32 status = 0;
67
68 status = clk_freq_controller_pmudatainit_super(g,
69 board_obj_ptr, ppmudata);
70 if (status)
71 return -1;
72
73 pfreq_cntlr_pi_set =
74 (struct nv_pmu_clk_clk_freq_controller_pi_boardobj_set *)
75 ppmudata;
76 pfreq_cntlr_pi = (struct clk_freq_controller_pi *)board_obj_ptr;
77
78 pfreq_cntlr_pi_set->prop_gain = pfreq_cntlr_pi->prop_gain;
79 pfreq_cntlr_pi_set->integ_gain = pfreq_cntlr_pi->integ_gain;
80 pfreq_cntlr_pi_set->integ_decay = pfreq_cntlr_pi->integ_decay;
81 pfreq_cntlr_pi_set->volt_delta_min = pfreq_cntlr_pi->volt_delta_min;
82 pfreq_cntlr_pi_set->volt_delta_max = pfreq_cntlr_pi->volt_delta_max;
83 pfreq_cntlr_pi_set->slowdown_pct_min = pfreq_cntlr_pi->slowdown_pct_min;
84 pfreq_cntlr_pi_set->bpoison = pfreq_cntlr_pi->bpoison;
85
86 return status;
87}
88
89static u32 clk_freq_controller_construct_super(struct gk20a *g,
90 struct boardobj **ppboardobj,
91 u16 size, void *pargs)
92{
93 struct clk_freq_controller *pfreq_cntlr = NULL;
94 struct clk_freq_controller *pfreq_cntlr_tmp = NULL;
95 u32 status = 0;
96
97 status = boardobj_construct_super(g, ppboardobj, size, pargs);
98 if (status)
99 return -EINVAL;
100
101 pfreq_cntlr_tmp = (struct clk_freq_controller *)pargs;
102 pfreq_cntlr = (struct clk_freq_controller *)*ppboardobj;
103
104 pfreq_cntlr->super.pmudatainit = clk_freq_controller_pmudatainit_super;
105
106 pfreq_cntlr->controller_id = pfreq_cntlr_tmp->controller_id;
107 pfreq_cntlr->clk_domain = pfreq_cntlr_tmp->clk_domain;
108 pfreq_cntlr->parts_freq_mode = pfreq_cntlr_tmp->parts_freq_mode;
109 pfreq_cntlr->freq_cap_noise_unaware_vmin_above =
110 pfreq_cntlr_tmp->freq_cap_noise_unaware_vmin_above;
111 pfreq_cntlr->freq_cap_noise_unaware_vmin_below =
112 pfreq_cntlr_tmp->freq_cap_noise_unaware_vmin_below;
113 pfreq_cntlr->freq_hyst_pos_mhz = pfreq_cntlr_tmp->freq_hyst_pos_mhz;
114 pfreq_cntlr->freq_hyst_neg_mhz = pfreq_cntlr_tmp->freq_hyst_neg_mhz;
115
116 return status;
117}
118
119static u32 clk_freq_controller_construct_pi(struct gk20a *g,
120 struct boardobj **ppboardobj,
121 u16 size, void *pargs)
122{
123 struct clk_freq_controller_pi *pfreq_cntlr_pi = NULL;
124 struct clk_freq_controller_pi *pfreq_cntlr_pi_tmp = NULL;
125 u32 status = 0;
126
127 status = clk_freq_controller_construct_super(g, ppboardobj,
128 size, pargs);
129 if (status)
130 return -EINVAL;
131
132 pfreq_cntlr_pi = (struct clk_freq_controller_pi *)*ppboardobj;
133 pfreq_cntlr_pi_tmp = (struct clk_freq_controller_pi *)pargs;
134
135 pfreq_cntlr_pi->super.super.pmudatainit =
136 clk_freq_controller_pmudatainit_pi;
137
138 pfreq_cntlr_pi->prop_gain = pfreq_cntlr_pi_tmp->prop_gain;
139 pfreq_cntlr_pi->integ_gain = pfreq_cntlr_pi_tmp->integ_gain;
140 pfreq_cntlr_pi->integ_decay = pfreq_cntlr_pi_tmp->integ_decay;
141 pfreq_cntlr_pi->volt_delta_min = pfreq_cntlr_pi_tmp->volt_delta_min;
142 pfreq_cntlr_pi->volt_delta_max = pfreq_cntlr_pi_tmp->volt_delta_max;
143 pfreq_cntlr_pi->slowdown_pct_min = pfreq_cntlr_pi_tmp->slowdown_pct_min;
144 pfreq_cntlr_pi->bpoison = pfreq_cntlr_pi_tmp->bpoison;
145
146 return status;
147}
148
149struct clk_freq_controller *clk_clk_freq_controller_construct(struct gk20a *g,
150 void *pargs)
151{
152 struct boardobj *board_obj_ptr = NULL;
153 u32 status = 0;
154
155 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_CLK_CLK_FREQ_CONTROLLER_TYPE_PI)
156 return NULL;
157
158 status = clk_freq_controller_construct_pi(g, &board_obj_ptr,
159 sizeof(struct clk_freq_controller_pi), pargs);
160 if (status)
161 return NULL;
162
163 return (struct clk_freq_controller *)board_obj_ptr;
164}
165
166
167static u32 clk_get_freq_controller_table(struct gk20a *g,
168 struct clk_freq_controllers *pclk_freq_controllers)
169{
170 u32 status = 0;
171 u8 *pfreq_controller_table_ptr = NULL;
172 struct vbios_fct_1x_header header = { 0 };
173 struct vbios_fct_1x_entry entry = { 0 };
174 u8 entry_idx;
175 u8 *entry_offset;
176 u32 freq_controller_id;
177 struct clk_freq_controller *pclk_freq_cntr = NULL;
178 struct clk_freq_controller *ptmp_freq_cntr = NULL;
179 struct clk_freq_controller_pi *ptmp_freq_cntr_pi = NULL;
180 struct clk_domain *pclk_domain;
181
182 struct freq_controller_data_type {
183 union {
184 struct boardobj board_obj;
185 struct clk_freq_controller freq_controller;
186 struct clk_freq_controller_pi freq_controller_pi;
187 };
188 } freq_controller_data;
189
190 if (g->ops.bios.get_perf_table_ptrs) {
191 pfreq_controller_table_ptr =
192 (u8 *)g->ops.bios.get_perf_table_ptrs(g,
193 g->bios.clock_token,
194 FREQUENCY_CONTROLLER_TABLE);
195 if (pfreq_controller_table_ptr == NULL) {
196 status = -EINVAL;
197 goto done;
198 }
199 } else {
200 status = -EINVAL;
201 goto done;
202 }
203
204 memcpy(&header, pfreq_controller_table_ptr,
205 sizeof(struct vbios_fct_1x_header));
206
207 pclk_freq_controllers->sampling_period_ms = header.sampling_period_ms;
208 pclk_freq_controllers->volt_policy_idx = 0;
209
210 /* Read in the entries. */
211 for (entry_idx = 0; entry_idx < header.entry_count; entry_idx++) {
212 entry_offset = (pfreq_controller_table_ptr +
213 header.header_size + (entry_idx * header.entry_size));
214
215 memset(&freq_controller_data, 0x0,
216 sizeof(struct freq_controller_data_type));
217 ptmp_freq_cntr = &freq_controller_data.freq_controller;
218 ptmp_freq_cntr_pi = &freq_controller_data.freq_controller_pi;
219
220 memcpy(&entry, entry_offset,
221 sizeof(struct vbios_fct_1x_entry));
222
223 if (!BIOS_GET_FIELD(entry.flags0,
224 NV_VBIOS_FCT_1X_ENTRY_FLAGS0_TYPE))
225 continue;
226
227 freq_controller_data.board_obj.type = (u8)BIOS_GET_FIELD(
228 entry.flags0, NV_VBIOS_FCT_1X_ENTRY_FLAGS0_TYPE);
229
230 ptmp_freq_cntr->controller_id =
231 (u8)BIOS_GET_FIELD(entry.param0,
232 NV_VBIOS_FCT_1X_ENTRY_PARAM0_ID);
233
234 freq_controller_id = ptmp_freq_cntr->controller_id;
235
236 pclk_domain = CLK_CLK_DOMAIN_GET((&g->clk_pmu),
237 (u32)entry.clk_domain_idx);
238 freq_controller_data.freq_controller.clk_domain =
239 pclk_domain->api_domain;
240
241 ptmp_freq_cntr->parts_freq_mode =
242 (u8)BIOS_GET_FIELD(entry.param0,
243 NV_VBIOS_FCT_1X_ENTRY_PARAM0_FREQ_MODE);
244
245 /* Populate PI specific data */
246 ptmp_freq_cntr_pi->slowdown_pct_min =
247 (u8)BIOS_GET_FIELD(entry.param1,
248 NV_VBIOS_FCT_1X_ENTRY_PARAM1_SLOWDOWN_PCT_MIN);
249
250 ptmp_freq_cntr_pi->bpoison =
251 BIOS_GET_FIELD(entry.param1,
252 NV_VBIOS_FCT_1X_ENTRY_PARAM1_POISON);
253
254 ptmp_freq_cntr_pi->prop_gain =
255 (s32)BIOS_GET_FIELD(entry.param2,
256 NV_VBIOS_FCT_1X_ENTRY_PARAM2_PROP_GAIN);
257
258 ptmp_freq_cntr_pi->integ_gain =
259 (s32)BIOS_GET_FIELD(entry.param3,
260 NV_VBIOS_FCT_1X_ENTRY_PARAM3_INTEG_GAIN);
261
262 ptmp_freq_cntr_pi->integ_decay =
263 (s32)BIOS_GET_FIELD(entry.param4,
264 NV_VBIOS_FCT_1X_ENTRY_PARAM4_INTEG_DECAY);
265
266 ptmp_freq_cntr_pi->volt_delta_min =
267 (s32)BIOS_GET_FIELD(entry.param5,
268 NV_VBIOS_FCT_1X_ENTRY_PARAM5_VOLT_DELTA_MIN);
269
270 ptmp_freq_cntr_pi->volt_delta_max =
271 (s32)BIOS_GET_FIELD(entry.param6,
272 NV_VBIOS_FCT_1X_ENTRY_PARAM6_VOLT_DELTA_MAX);
273
274 ptmp_freq_cntr->freq_cap_noise_unaware_vmin_above =
275 (s16)BIOS_GET_FIELD(entry.param7,
276 NV_VBIOS_FCT_1X_ENTRY_PARAM7_FREQ_CAP_VF);
277
278 ptmp_freq_cntr->freq_cap_noise_unaware_vmin_below =
279 (s16)BIOS_GET_FIELD(entry.param7,
280 NV_VBIOS_FCT_1X_ENTRY_PARAM7_FREQ_CAP_VMIN);
281
282 ptmp_freq_cntr->freq_hyst_pos_mhz =
283 (s16)BIOS_GET_FIELD(entry.param8,
284 NV_VBIOS_FCT_1X_ENTRY_PARAM8_FREQ_HYST_POS);
285 ptmp_freq_cntr->freq_hyst_neg_mhz =
286 (s16)BIOS_GET_FIELD(entry.param8,
287 NV_VBIOS_FCT_1X_ENTRY_PARAM8_FREQ_HYST_NEG);
288
289 if (ptmp_freq_cntr_pi->volt_delta_max <
290 ptmp_freq_cntr_pi->volt_delta_min)
291 goto done;
292
293 pclk_freq_cntr = clk_clk_freq_controller_construct(g,
294 (void *)&freq_controller_data);
295
296 if (pclk_freq_cntr == NULL) {
297 gk20a_err(dev_from_gk20a(g),
298 "unable to construct clock freq cntlr boardobj for %d",
299 entry_idx);
300 status = -EINVAL;
301 goto done;
302 }
303
304 status = boardobjgrp_objinsert(
305 &pclk_freq_controllers->super.super,
306 (struct boardobj *)pclk_freq_cntr, entry_idx);
307 if (status) {
308 gk20a_err(dev_from_gk20a(g),
309 "unable to insert clock freq cntlr boardobj for");
310 status = -EINVAL;
311 goto done;
312 }
313
314 }
315
316done:
317 return status;
318}
319
320u32 clk_freq_controller_pmu_setup(struct gk20a *g)
321{
322 u32 status;
323 struct boardobjgrp *pboardobjgrp = NULL;
324
325 gk20a_dbg_info("");
326
327 pboardobjgrp = &g->clk_pmu.clk_freq_controllers.super.super;
328
329 if (!pboardobjgrp->bconstructed)
330 return -EINVAL;
331
332 status = pboardobjgrp->pmuinithandle(g, pboardobjgrp);
333
334 gk20a_dbg_info("Done");
335 return status;
336}
337
338static u32 _clk_freq_controller_devgrp_pmudata_instget(struct gk20a *g,
339 struct nv_pmu_boardobjgrp *pmuboardobjgrp,
340 struct nv_pmu_boardobj **ppboardobjpmudata,
341 u8 idx)
342{
343 struct nv_pmu_clk_clk_freq_controller_boardobj_grp_set *pgrp_set =
344 (struct nv_pmu_clk_clk_freq_controller_boardobj_grp_set *)
345 pmuboardobjgrp;
346
347 gk20a_dbg_info("");
348
349 /*check whether pmuboardobjgrp has a valid boardobj in index*/
350 if (((u32)BIT(idx) &
351 pgrp_set->hdr.data.super.obj_mask.super.data[0]) == 0)
352 return -EINVAL;
353
354 *ppboardobjpmudata = (struct nv_pmu_boardobj *)
355 &pgrp_set->objects[idx].data.board_obj;
356 gk20a_dbg_info(" Done");
357 return 0;
358}
359
360static u32 _clk_freq_controllers_pmudatainit(struct gk20a *g,
361 struct boardobjgrp *pboardobjgrp,
362 struct nv_pmu_boardobjgrp_super *pboardobjgrppmu)
363{
364 struct nv_pmu_clk_clk_freq_controller_boardobjgrp_set_header *pset =
365 (struct nv_pmu_clk_clk_freq_controller_boardobjgrp_set_header *)
366 pboardobjgrppmu;
367 struct clk_freq_controllers *pcntrs =
368 (struct clk_freq_controllers *)pboardobjgrp;
369 u32 status = 0;
370
371 status = boardobjgrp_pmudatainit_e32(g, pboardobjgrp, pboardobjgrppmu);
372 if (status) {
373 gk20a_err(dev_from_gk20a(g),
374 "error updating pmu boardobjgrp for clk freq ctrs 0x%x",
375 status);
376 goto done;
377 }
378 pset->sampling_period_ms = pcntrs->sampling_period_ms;
379 pset->volt_policy_idx = pcntrs->volt_policy_idx;
380
381done:
382 return status;
383}
384
385u32 clk_freq_controller_sw_setup(struct gk20a *g)
386{
387 u32 status = 0;
388 struct boardobjgrp *pboardobjgrp = NULL;
389 struct clk_freq_controllers *pclk_freq_controllers;
390 struct avfsfllobjs *pfllobjs = &(g->clk_pmu.avfs_fllobjs);
391 struct fll_device *pfll;
392 struct clk_freq_controller *pclkfreqctrl;
393 u8 i;
394 u8 j;
395
396 gk20a_dbg_info("");
397
398 pclk_freq_controllers = &g->clk_pmu.clk_freq_controllers;
399 status = boardobjgrpconstruct_e32(&pclk_freq_controllers->super);
400 if (status) {
401 gk20a_err(dev_from_gk20a(g),
402 "error creating boardobjgrp for clk FCT, status - 0x%x",
403 status);
404 goto done;
405 }
406
407 pboardobjgrp = &g->clk_pmu.clk_freq_controllers.super.super;
408
409 pboardobjgrp->pmudatainit = _clk_freq_controllers_pmudatainit;
410 pboardobjgrp->pmudatainstget =
411 _clk_freq_controller_devgrp_pmudata_instget;
412 pboardobjgrp->pmustatusinstget = NULL;
413
414 /* Initialize mask to zero.*/
415 boardobjgrpmask_e32_init(&pclk_freq_controllers->freq_ctrl_load_mask,
416 NULL);
417
418 BOARDOBJGRP_PMU_CONSTRUCT(pboardobjgrp, CLK, CLK_FREQ_CONTROLLER);
419
420 status = BOARDOBJGRP_PMU_CMD_GRP_SET_CONSTRUCT(g, pboardobjgrp,
421 clk, CLK, clk_freq_controller, CLK_FREQ_CONTROLLER);
422 if (status) {
423 gk20a_err(dev_from_gk20a(g),
424 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
425 status);
426 goto done;
427 }
428
429 status = clk_get_freq_controller_table(g, pclk_freq_controllers);
430 if (status) {
431 gk20a_err(dev_from_gk20a(g),
432 "error reading freq controller table - 0x%x",
433 status);
434 goto done;
435 }
436
437 BOARDOBJGRP_FOR_EACH(&(pclk_freq_controllers->super.super),
438 struct clk_freq_controller *, pclkfreqctrl, i) {
439 pfll = NULL;
440 j = 0;
441 BOARDOBJGRP_FOR_EACH(&(pfllobjs->super.super),
442 struct fll_device *, pfll, j) {
443 if (pclkfreqctrl->controller_id == pfll->id) {
444 pfll->freq_ctrl_idx = i;
445 break;
446 }
447 }
448 boardobjgrpmask_bitset(&pclk_freq_controllers->
449 freq_ctrl_load_mask.super, i);
450 }
451done:
452 gk20a_dbg_info(" done status %x", status);
453 return status;
454}
diff --git a/drivers/gpu/nvgpu/clk/clk_freq_controller.h b/drivers/gpu/nvgpu/clk/clk_freq_controller.h
new file mode 100644
index 00000000..957a4f08
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk_freq_controller.h
@@ -0,0 +1,74 @@
1/*
2* Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
3*
4* This program is free software; you can redistribute it and/or modify it
5* under the terms and conditions of the GNU General Public License,
6* version 2, as published by the Free Software Foundation.
7*
8* This program is distributed in the hope it will be useful, but WITHOUT
9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11* more details.
12*/
13
14#ifndef _CLK_FREQ_CONTROLLER_H_
15#define _CLK_FREQ_CONTROLLER_H_
16
17#define CTRL_CLK_CLK_FREQ_CONTROLLER_ID_SYS 0x00
18#define CTRL_CLK_CLK_FREQ_CONTROLLER_ID_LTC 0x01
19#define CTRL_CLK_CLK_FREQ_CONTROLLER_ID_XBAR 0x02
20#define CTRL_CLK_CLK_FREQ_CONTROLLER_ID_GPC0 0x03
21#define CTRL_CLK_CLK_FREQ_CONTROLLER_ID_GPC1 0x04
22#define CTRL_CLK_CLK_FREQ_CONTROLLER_ID_GPC2 0x05
23#define CTRL_CLK_CLK_FREQ_CONTROLLER_ID_GPC3 0x06
24#define CTRL_CLK_CLK_FREQ_CONTROLLER_ID_GPC4 0x07
25#define CTRL_CLK_CLK_FREQ_CONTROLLER_ID_GPC5 0x08
26#define CTRL_CLK_CLK_FREQ_CONTROLLER_ID_GPCS 0x09
27
28#define CTRL_CLK_CLK_FREQ_CONTROLLER_MASK_UNICAST_GPC \
29 (BIT(CTRL_CLK_CLK_FREQ_CONTROLLER_ID_GPC0) | \
30 BIT(CTRL_CLK_CLK_FREQ_CONTROLLER_ID_GPC1) | \
31 BIT(CTRL_CLK_CLK_FREQ_CONTROLLER_ID_GPC2) | \
32 BIT(CTRL_CLK_CLK_FREQ_CONTROLLER_ID_GPC3) | \
33 BIT(CTRL_CLK_CLK_FREQ_CONTROLLER_ID_GPC4) | \
34 BIT(CTRL_CLK_CLK_FREQ_CONTROLLER_ID_GPC5))
35
36#define CTRL_CLK_CLK_FREQ_CONTROLLER_TYPE_DISABLED 0x00
37#define CTRL_CLK_CLK_FREQ_CONTROLLER_TYPE_PI 0x01
38
39
40struct clk_freq_controller {
41 struct boardobj super;
42 u8 controller_id;
43 u8 parts_freq_mode;
44 bool bdisable;
45 u32 clk_domain;
46 s16 freq_cap_noise_unaware_vmin_above;
47 s16 freq_cap_noise_unaware_vmin_below;
48 s16 freq_hyst_pos_mhz;
49 s16 freq_hyst_neg_mhz;
50};
51
52struct clk_freq_controller_pi {
53 struct clk_freq_controller super;
54 s32 prop_gain;
55 s32 integ_gain;
56 s32 integ_decay;
57 s32 volt_delta_min;
58 s32 volt_delta_max;
59 u8 slowdown_pct_min;
60 bool bpoison;
61};
62
63struct clk_freq_controllers {
64 struct boardobjgrp_e32 super;
65 u32 sampling_period_ms;
66 struct boardobjgrpmask_e32 freq_ctrl_load_mask;
67 u8 volt_policy_idx;
68 void *pprereq_load;
69};
70
71u32 clk_freq_controller_sw_setup(struct gk20a *g);
72u32 clk_freq_controller_pmu_setup(struct gk20a *g);
73
74#endif
diff --git a/drivers/gpu/nvgpu/include/bios.h b/drivers/gpu/nvgpu/include/bios.h
index 02991db9..f3939d14 100644
--- a/drivers/gpu/nvgpu/include/bios.h
+++ b/drivers/gpu/nvgpu/include/bios.h
@@ -842,4 +842,87 @@ struct therm_channel_1x_entry {
842#define NV_VBIOS_THERM_CHANNEL_1X_ENTRY_PARAM1_DEVICE_PROVIDER_INDEX_MASK 0xFF 842#define NV_VBIOS_THERM_CHANNEL_1X_ENTRY_PARAM1_DEVICE_PROVIDER_INDEX_MASK 0xFF
843#define NV_VBIOS_THERM_CHANNEL_1X_ENTRY_PARAM1_DEVICE_PROVIDER_INDEX_SHIFT 0 843#define NV_VBIOS_THERM_CHANNEL_1X_ENTRY_PARAM1_DEVICE_PROVIDER_INDEX_SHIFT 0
844 844
845/* Frequency Controller Table */
846struct vbios_fct_1x_header {
847 u8 version;
848 u8 header_size;
849 u8 entry_size;
850 u8 entry_count;
851 u16 sampling_period_ms;
852} __packed;
853
854struct vbios_fct_1x_entry {
855 u8 flags0;
856 u8 clk_domain_idx;
857 u16 param0;
858 u16 param1;
859 u32 param2;
860 u32 param3;
861 u32 param4;
862 u32 param5;
863 u32 param6;
864 u32 param7;
865 u32 param8;
866} __packed;
867
868#define NV_VBIOS_FCT_1X_ENTRY_FLAGS0_TYPE_MASK GENMASK(3, 0)
869#define NV_VBIOS_FCT_1X_ENTRY_FLAGS0_TYPE_SHIFT 0
870#define NV_VBIOS_FCT_1X_ENTRY_FLAGS0_TYPE_DISABLED 0x0
871#define NV_VBIOS_FCT_1X_ENTRY_FLAGS0_TYPE_PI 0x1
872
873#define NV_VBIOS_FCT_1X_ENTRY_PARAM0_ID_MASK GENMASK(7, 0)
874#define NV_VBIOS_FCT_1X_ENTRY_PARAM0_ID_SHIFT 0
875#define NV_VBIOS_FCT_1X_ENTRY_PARAM0_ID_SYS 0x00
876#define NV_VBIOS_FCT_1X_ENTRY_PARAM0_ID_LTC 0x01
877#define NV_VBIOS_FCT_1X_ENTRY_PARAM0_ID_XBAR 0x02
878#define NV_VBIOS_FCT_1X_ENTRY_PARAM0_ID_GPC0 0x03
879#define NV_VBIOS_FCT_1X_ENTRY_PARAM0_ID_GPC1 0x04
880#define NV_VBIOS_FCT_1X_ENTRY_PARAM0_ID_GPC2 0x05
881#define NV_VBIOS_FCT_1X_ENTRY_PARAM0_ID_GPC3 0x06
882#define NV_VBIOS_FCT_1X_ENTRY_PARAM0_ID_GPC4 0x07
883#define NV_VBIOS_FCT_1X_ENTRY_PARAM0_ID_GPC5 0x08
884#define NV_VBIOS_FCT_1X_ENTRY_PARAM0_ID_GPCS 0x09
885
886#define NV_VBIOS_FCT_1X_ENTRY_PARAM0_FREQ_MODE_MASK GENMASK(9, 8)
887#define NV_VBIOS_FCT_1X_ENTRY_PARAM0_FREQ_MODE_SHIFT 8
888#define NV_VBIOS_FCT_1X_ENTRY_PARAM0_FREQ_MODE_BCAST 0x0
889#define NV_VBIOS_FCT_1X_ENTRY_PARAM0_FREQ_MODE_MIN 0x1
890#define NV_VBIOS_FCT_1X_ENTRY_PARAM0_FREQ_MODE_MAX 0x2
891#define NV_VBIOS_FCT_1X_ENTRY_PARAM0_FREQ_MODE_AVG 0x3
892
893#define NV_VBIOS_FCT_1X_ENTRY_PARAM1_SLOWDOWN_PCT_MIN_MASK GENMASK(7, 0)
894#define NV_VBIOS_FCT_1X_ENTRY_PARAM1_SLOWDOWN_PCT_MIN_SHIFT 0
895
896#define NV_VBIOS_FCT_1X_ENTRY_PARAM1_POISON_MASK GENMASK(8, 8)
897#define NV_VBIOS_FCT_1X_ENTRY_PARAM1_POISON_SHIFT 8
898#define NV_VBIOS_FCT_1X_ENTRY_PARAM1_POISON_NO 0x0
899#define NV_VBIOS_FCT_1X_ENTRY_PARAM1_POISON_YES 0x1
900
901#define NV_VBIOS_FCT_1X_ENTRY_PARAM2_PROP_GAIN_MASK GENMASK(31, 0)
902#define NV_VBIOS_FCT_1X_ENTRY_PARAM2_PROP_GAIN_SHIFT 0
903
904#define NV_VBIOS_FCT_1X_ENTRY_PARAM3_INTEG_GAIN_MASK GENMASK(31, 0)
905#define NV_VBIOS_FCT_1X_ENTRY_PARAM3_INTEG_GAIN_SHIFT 0
906
907
908#define NV_VBIOS_FCT_1X_ENTRY_PARAM4_INTEG_DECAY_MASK GENMASK(31, 0)
909#define NV_VBIOS_FCT_1X_ENTRY_PARAM4_INTEG_DECAY_SHIFT 0
910
911#define NV_VBIOS_FCT_1X_ENTRY_PARAM5_VOLT_DELTA_MIN_MASK GENMASK(31, 0)
912#define NV_VBIOS_FCT_1X_ENTRY_PARAM5_VOLT_DELTA_MIN_SHIFT 0
913
914
915#define NV_VBIOS_FCT_1X_ENTRY_PARAM6_VOLT_DELTA_MAX_MASK GENMASK(31, 0)
916#define NV_VBIOS_FCT_1X_ENTRY_PARAM6_VOLT_DELTA_MAX_SHIFT 0
917
918#define NV_VBIOS_FCT_1X_ENTRY_PARAM7_FREQ_CAP_VF_MASK GENMASK(15, 0)
919#define NV_VBIOS_FCT_1X_ENTRY_PARAM7_FREQ_CAP_VF_SHIFT 0
920#define NV_VBIOS_FCT_1X_ENTRY_PARAM7_FREQ_CAP_VMIN_MASK GENMASK(31, 16)
921#define NV_VBIOS_FCT_1X_ENTRY_PARAM7_FREQ_CAP_VMIN_SHIFT 16
922
923#define NV_VBIOS_FCT_1X_ENTRY_PARAM8_FREQ_HYST_POS_MASK GENMASK(15, 0)
924#define NV_VBIOS_FCT_1X_ENTRY_PARAM8_FREQ_HYST_POS_SHIFT 0
925#define NV_VBIOS_FCT_1X_ENTRY_PARAM8_FREQ_HYST_NEG_MASK GENMASK(31, 16)
926#define NV_VBIOS_FCT_1X_ENTRY_PARAM8_FREQ_HYST_NEG_SHIFT 16
927
845#endif 928#endif
diff --git a/drivers/gpu/nvgpu/pstate/pstate.c b/drivers/gpu/nvgpu/pstate/pstate.c
index cf758023..cca6c445 100644
--- a/drivers/gpu/nvgpu/pstate/pstate.c
+++ b/drivers/gpu/nvgpu/pstate/pstate.c
@@ -79,6 +79,11 @@ int gk20a_init_pstate_support(struct gk20a *g)
79 return err; 79 return err;
80 80
81 err = pmgr_domain_sw_setup(g); 81 err = pmgr_domain_sw_setup(g);
82 if (err)
83 return err;
84
85 err = clk_freq_controller_sw_setup(g);
86
82 return err; 87 return err;
83} 88}
84 89
@@ -141,6 +146,10 @@ int gk20a_init_pstate_pmu_support(struct gk20a *g)
141 if (err) 146 if (err)
142 return err; 147 return err;
143 148
149 err = clk_freq_controller_pmu_setup(g);
150 if (err)
151 return err;
152
144 err = clk_pmu_vin_load(g); 153 err = clk_pmu_vin_load(g);
145 if (err) 154 if (err)
146 return err; 155 return err;