summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/clk/clk_freq_controller.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/nvgpu/clk/clk_freq_controller.c')
-rw-r--r--drivers/gpu/nvgpu/clk/clk_freq_controller.c455
1 files changed, 455 insertions, 0 deletions
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..f5c1e929
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk_freq_controller.c
@@ -0,0 +1,455 @@
1/*
2 * Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
21 */
22
23#include <nvgpu/bios.h>
24
25#include "gk20a/gk20a.h"
26#include "clk.h"
27#include "clk_fll.h"
28#include "clk_domain.h"
29#include "clk_freq_controller.h"
30#include "boardobj/boardobjgrp.h"
31#include "boardobj/boardobjgrp_e32.h"
32#include "ctrl/ctrlclk.h"
33#include "ctrl/ctrlvolt.h"
34
35static u32 clk_freq_controller_pmudatainit_super(struct gk20a *g,
36 struct boardobj *board_obj_ptr,
37 struct nv_pmu_boardobj *ppmudata)
38{
39 struct nv_pmu_clk_clk_freq_controller_boardobj_set *pfreq_cntlr_set;
40 struct clk_freq_controller *pfreq_cntlr;
41 u32 status = 0;
42
43 status = boardobj_pmudatainit_super(g, board_obj_ptr, ppmudata);
44 if (status)
45 return status;
46
47 pfreq_cntlr_set =
48 (struct nv_pmu_clk_clk_freq_controller_boardobj_set *)ppmudata;
49 pfreq_cntlr = (struct clk_freq_controller *)board_obj_ptr;
50
51 pfreq_cntlr_set->controller_id = pfreq_cntlr->controller_id;
52 pfreq_cntlr_set->clk_domain = pfreq_cntlr->clk_domain;
53 pfreq_cntlr_set->parts_freq_mode = pfreq_cntlr->parts_freq_mode;
54 pfreq_cntlr_set->bdisable = pfreq_cntlr->bdisable;
55 pfreq_cntlr_set->freq_cap_noise_unaware_vmin_above =
56 pfreq_cntlr->freq_cap_noise_unaware_vmin_above;
57 pfreq_cntlr_set->freq_cap_noise_unaware_vmin_below =
58 pfreq_cntlr->freq_cap_noise_unaware_vmin_below;
59 pfreq_cntlr_set->freq_hyst_pos_mhz = pfreq_cntlr->freq_hyst_pos_mhz;
60 pfreq_cntlr_set->freq_hyst_neg_mhz = pfreq_cntlr->freq_hyst_neg_mhz;
61
62 return status;
63}
64
65static u32 clk_freq_controller_pmudatainit_pi(struct gk20a *g,
66 struct boardobj *board_obj_ptr,
67 struct nv_pmu_boardobj *ppmudata)
68{
69 struct nv_pmu_clk_clk_freq_controller_pi_boardobj_set
70 *pfreq_cntlr_pi_set;
71 struct clk_freq_controller_pi *pfreq_cntlr_pi;
72 u32 status = 0;
73
74 status = clk_freq_controller_pmudatainit_super(g,
75 board_obj_ptr, ppmudata);
76 if (status)
77 return -1;
78
79 pfreq_cntlr_pi_set =
80 (struct nv_pmu_clk_clk_freq_controller_pi_boardobj_set *)
81 ppmudata;
82 pfreq_cntlr_pi = (struct clk_freq_controller_pi *)board_obj_ptr;
83
84 pfreq_cntlr_pi_set->prop_gain = pfreq_cntlr_pi->prop_gain;
85 pfreq_cntlr_pi_set->integ_gain = pfreq_cntlr_pi->integ_gain;
86 pfreq_cntlr_pi_set->integ_decay = pfreq_cntlr_pi->integ_decay;
87 pfreq_cntlr_pi_set->volt_delta_min = pfreq_cntlr_pi->volt_delta_min;
88 pfreq_cntlr_pi_set->volt_delta_max = pfreq_cntlr_pi->volt_delta_max;
89 pfreq_cntlr_pi_set->slowdown_pct_min = pfreq_cntlr_pi->slowdown_pct_min;
90 pfreq_cntlr_pi_set->bpoison = pfreq_cntlr_pi->bpoison;
91
92 return status;
93}
94
95static u32 clk_freq_controller_construct_super(struct gk20a *g,
96 struct boardobj **ppboardobj,
97 u16 size, void *pargs)
98{
99 struct clk_freq_controller *pfreq_cntlr = NULL;
100 struct clk_freq_controller *pfreq_cntlr_tmp = NULL;
101 u32 status = 0;
102
103 status = boardobj_construct_super(g, ppboardobj, size, pargs);
104 if (status)
105 return -EINVAL;
106
107 pfreq_cntlr_tmp = (struct clk_freq_controller *)pargs;
108 pfreq_cntlr = (struct clk_freq_controller *)*ppboardobj;
109
110 pfreq_cntlr->super.pmudatainit = clk_freq_controller_pmudatainit_super;
111
112 pfreq_cntlr->controller_id = pfreq_cntlr_tmp->controller_id;
113 pfreq_cntlr->clk_domain = pfreq_cntlr_tmp->clk_domain;
114 pfreq_cntlr->parts_freq_mode = pfreq_cntlr_tmp->parts_freq_mode;
115 pfreq_cntlr->freq_cap_noise_unaware_vmin_above =
116 pfreq_cntlr_tmp->freq_cap_noise_unaware_vmin_above;
117 pfreq_cntlr->freq_cap_noise_unaware_vmin_below =
118 pfreq_cntlr_tmp->freq_cap_noise_unaware_vmin_below;
119 pfreq_cntlr->freq_hyst_pos_mhz = pfreq_cntlr_tmp->freq_hyst_pos_mhz;
120 pfreq_cntlr->freq_hyst_neg_mhz = pfreq_cntlr_tmp->freq_hyst_neg_mhz;
121
122 return status;
123}
124
125static u32 clk_freq_controller_construct_pi(struct gk20a *g,
126 struct boardobj **ppboardobj,
127 u16 size, void *pargs)
128{
129 struct clk_freq_controller_pi *pfreq_cntlr_pi = NULL;
130 struct clk_freq_controller_pi *pfreq_cntlr_pi_tmp = NULL;
131 u32 status = 0;
132
133 status = clk_freq_controller_construct_super(g, ppboardobj,
134 size, pargs);
135 if (status)
136 return -EINVAL;
137
138 pfreq_cntlr_pi = (struct clk_freq_controller_pi *)*ppboardobj;
139 pfreq_cntlr_pi_tmp = (struct clk_freq_controller_pi *)pargs;
140
141 pfreq_cntlr_pi->super.super.pmudatainit =
142 clk_freq_controller_pmudatainit_pi;
143
144 pfreq_cntlr_pi->prop_gain = pfreq_cntlr_pi_tmp->prop_gain;
145 pfreq_cntlr_pi->integ_gain = pfreq_cntlr_pi_tmp->integ_gain;
146 pfreq_cntlr_pi->integ_decay = pfreq_cntlr_pi_tmp->integ_decay;
147 pfreq_cntlr_pi->volt_delta_min = pfreq_cntlr_pi_tmp->volt_delta_min;
148 pfreq_cntlr_pi->volt_delta_max = pfreq_cntlr_pi_tmp->volt_delta_max;
149 pfreq_cntlr_pi->slowdown_pct_min = pfreq_cntlr_pi_tmp->slowdown_pct_min;
150 pfreq_cntlr_pi->bpoison = pfreq_cntlr_pi_tmp->bpoison;
151
152 return status;
153}
154
155static struct clk_freq_controller *clk_clk_freq_controller_construct(
156 struct gk20a *g,
157 void *pargs)
158{
159 struct boardobj *board_obj_ptr = NULL;
160 u32 status = 0;
161
162 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_CLK_CLK_FREQ_CONTROLLER_TYPE_PI)
163 return NULL;
164
165 status = clk_freq_controller_construct_pi(g, &board_obj_ptr,
166 sizeof(struct clk_freq_controller_pi), pargs);
167 if (status)
168 return NULL;
169
170 return (struct clk_freq_controller *)board_obj_ptr;
171}
172
173
174static u32 clk_get_freq_controller_table(struct gk20a *g,
175 struct clk_freq_controllers *pclk_freq_controllers)
176{
177 u32 status = 0;
178 u8 *pfreq_controller_table_ptr = NULL;
179 struct vbios_fct_1x_header header = { 0 };
180 struct vbios_fct_1x_entry entry = { 0 };
181 u8 entry_idx;
182 u8 *entry_offset;
183 u32 freq_controller_id;
184 struct clk_freq_controller *pclk_freq_cntr = NULL;
185 struct clk_freq_controller *ptmp_freq_cntr = NULL;
186 struct clk_freq_controller_pi *ptmp_freq_cntr_pi = NULL;
187 struct clk_domain *pclk_domain;
188
189 struct freq_controller_data_type {
190 union {
191 struct boardobj board_obj;
192 struct clk_freq_controller freq_controller;
193 struct clk_freq_controller_pi freq_controller_pi;
194 };
195 } freq_controller_data;
196
197 pfreq_controller_table_ptr =
198 (u8 *)nvgpu_bios_get_perf_table_ptrs(g,
199 g->bios.clock_token,
200 FREQUENCY_CONTROLLER_TABLE);
201 if (pfreq_controller_table_ptr == NULL) {
202 status = -EINVAL;
203 goto done;
204 }
205
206 memcpy(&header, pfreq_controller_table_ptr,
207 sizeof(struct vbios_fct_1x_header));
208
209 pclk_freq_controllers->sampling_period_ms = header.sampling_period_ms;
210 pclk_freq_controllers->volt_policy_idx = 0;
211
212 /* Read in the entries. */
213 for (entry_idx = 0; entry_idx < header.entry_count; entry_idx++) {
214 entry_offset = (pfreq_controller_table_ptr +
215 header.header_size + (entry_idx * header.entry_size));
216
217 memset(&freq_controller_data, 0x0,
218 sizeof(struct freq_controller_data_type));
219 ptmp_freq_cntr = &freq_controller_data.freq_controller;
220 ptmp_freq_cntr_pi = &freq_controller_data.freq_controller_pi;
221
222 memcpy(&entry, entry_offset,
223 sizeof(struct vbios_fct_1x_entry));
224
225 if (!BIOS_GET_FIELD(entry.flags0,
226 NV_VBIOS_FCT_1X_ENTRY_FLAGS0_TYPE))
227 continue;
228
229 freq_controller_data.board_obj.type = (u8)BIOS_GET_FIELD(
230 entry.flags0, NV_VBIOS_FCT_1X_ENTRY_FLAGS0_TYPE);
231
232 ptmp_freq_cntr->controller_id =
233 (u8)BIOS_GET_FIELD(entry.param0,
234 NV_VBIOS_FCT_1X_ENTRY_PARAM0_ID);
235
236 freq_controller_id = ptmp_freq_cntr->controller_id;
237
238 pclk_domain = CLK_CLK_DOMAIN_GET((&g->clk_pmu),
239 (u32)entry.clk_domain_idx);
240 freq_controller_data.freq_controller.clk_domain =
241 pclk_domain->api_domain;
242
243 ptmp_freq_cntr->parts_freq_mode =
244 (u8)BIOS_GET_FIELD(entry.param0,
245 NV_VBIOS_FCT_1X_ENTRY_PARAM0_FREQ_MODE);
246
247 /* Populate PI specific data */
248 ptmp_freq_cntr_pi->slowdown_pct_min =
249 (u8)BIOS_GET_FIELD(entry.param1,
250 NV_VBIOS_FCT_1X_ENTRY_PARAM1_SLOWDOWN_PCT_MIN);
251
252 ptmp_freq_cntr_pi->bpoison =
253 BIOS_GET_FIELD(entry.param1,
254 NV_VBIOS_FCT_1X_ENTRY_PARAM1_POISON);
255
256 ptmp_freq_cntr_pi->prop_gain =
257 (s32)BIOS_GET_FIELD(entry.param2,
258 NV_VBIOS_FCT_1X_ENTRY_PARAM2_PROP_GAIN);
259
260 ptmp_freq_cntr_pi->integ_gain =
261 (s32)BIOS_GET_FIELD(entry.param3,
262 NV_VBIOS_FCT_1X_ENTRY_PARAM3_INTEG_GAIN);
263
264 ptmp_freq_cntr_pi->integ_decay =
265 (s32)BIOS_GET_FIELD(entry.param4,
266 NV_VBIOS_FCT_1X_ENTRY_PARAM4_INTEG_DECAY);
267
268 ptmp_freq_cntr_pi->volt_delta_min =
269 (s32)BIOS_GET_FIELD(entry.param5,
270 NV_VBIOS_FCT_1X_ENTRY_PARAM5_VOLT_DELTA_MIN);
271
272 ptmp_freq_cntr_pi->volt_delta_max =
273 (s32)BIOS_GET_FIELD(entry.param6,
274 NV_VBIOS_FCT_1X_ENTRY_PARAM6_VOLT_DELTA_MAX);
275
276 ptmp_freq_cntr->freq_cap_noise_unaware_vmin_above =
277 (s16)BIOS_GET_FIELD(entry.param7,
278 NV_VBIOS_FCT_1X_ENTRY_PARAM7_FREQ_CAP_VF);
279
280 ptmp_freq_cntr->freq_cap_noise_unaware_vmin_below =
281 (s16)BIOS_GET_FIELD(entry.param7,
282 NV_VBIOS_FCT_1X_ENTRY_PARAM7_FREQ_CAP_VMIN);
283
284 ptmp_freq_cntr->freq_hyst_pos_mhz =
285 (s16)BIOS_GET_FIELD(entry.param8,
286 NV_VBIOS_FCT_1X_ENTRY_PARAM8_FREQ_HYST_POS);
287 ptmp_freq_cntr->freq_hyst_neg_mhz =
288 (s16)BIOS_GET_FIELD(entry.param8,
289 NV_VBIOS_FCT_1X_ENTRY_PARAM8_FREQ_HYST_NEG);
290
291 if (ptmp_freq_cntr_pi->volt_delta_max <
292 ptmp_freq_cntr_pi->volt_delta_min)
293 goto done;
294
295 pclk_freq_cntr = clk_clk_freq_controller_construct(g,
296 (void *)&freq_controller_data);
297
298 if (pclk_freq_cntr == NULL) {
299 nvgpu_err(g,
300 "unable to construct clock freq cntlr boardobj for %d",
301 entry_idx);
302 status = -EINVAL;
303 goto done;
304 }
305
306 status = boardobjgrp_objinsert(
307 &pclk_freq_controllers->super.super,
308 (struct boardobj *)pclk_freq_cntr, entry_idx);
309 if (status) {
310 nvgpu_err(g,
311 "unable to insert clock freq cntlr boardobj for");
312 status = -EINVAL;
313 goto done;
314 }
315
316 }
317
318done:
319 return status;
320}
321
322u32 clk_freq_controller_pmu_setup(struct gk20a *g)
323{
324 u32 status;
325 struct boardobjgrp *pboardobjgrp = NULL;
326
327 gk20a_dbg_info("");
328
329 pboardobjgrp = &g->clk_pmu.clk_freq_controllers.super.super;
330
331 if (!pboardobjgrp->bconstructed)
332 return -EINVAL;
333
334 status = pboardobjgrp->pmuinithandle(g, pboardobjgrp);
335
336 gk20a_dbg_info("Done");
337 return status;
338}
339
340static u32 _clk_freq_controller_devgrp_pmudata_instget(struct gk20a *g,
341 struct nv_pmu_boardobjgrp *pmuboardobjgrp,
342 struct nv_pmu_boardobj **ppboardobjpmudata,
343 u8 idx)
344{
345 struct nv_pmu_clk_clk_freq_controller_boardobj_grp_set *pgrp_set =
346 (struct nv_pmu_clk_clk_freq_controller_boardobj_grp_set *)
347 pmuboardobjgrp;
348
349 gk20a_dbg_info("");
350
351 /*check whether pmuboardobjgrp has a valid boardobj in index*/
352 if (((u32)BIT(idx) &
353 pgrp_set->hdr.data.super.obj_mask.super.data[0]) == 0)
354 return -EINVAL;
355
356 *ppboardobjpmudata = (struct nv_pmu_boardobj *)
357 &pgrp_set->objects[idx].data.board_obj;
358 gk20a_dbg_info(" Done");
359 return 0;
360}
361
362static u32 _clk_freq_controllers_pmudatainit(struct gk20a *g,
363 struct boardobjgrp *pboardobjgrp,
364 struct nv_pmu_boardobjgrp_super *pboardobjgrppmu)
365{
366 struct nv_pmu_clk_clk_freq_controller_boardobjgrp_set_header *pset =
367 (struct nv_pmu_clk_clk_freq_controller_boardobjgrp_set_header *)
368 pboardobjgrppmu;
369 struct clk_freq_controllers *pcntrs =
370 (struct clk_freq_controllers *)pboardobjgrp;
371 u32 status = 0;
372
373 status = boardobjgrp_pmudatainit_e32(g, pboardobjgrp, pboardobjgrppmu);
374 if (status) {
375 nvgpu_err(g,
376 "error updating pmu boardobjgrp for clk freq ctrs 0x%x",
377 status);
378 goto done;
379 }
380 pset->sampling_period_ms = pcntrs->sampling_period_ms;
381 pset->volt_policy_idx = pcntrs->volt_policy_idx;
382
383done:
384 return status;
385}
386
387u32 clk_freq_controller_sw_setup(struct gk20a *g)
388{
389 u32 status = 0;
390 struct boardobjgrp *pboardobjgrp = NULL;
391 struct clk_freq_controllers *pclk_freq_controllers;
392 struct avfsfllobjs *pfllobjs = &(g->clk_pmu.avfs_fllobjs);
393 struct fll_device *pfll;
394 struct clk_freq_controller *pclkfreqctrl;
395 u8 i;
396 u8 j;
397
398 gk20a_dbg_info("");
399
400 pclk_freq_controllers = &g->clk_pmu.clk_freq_controllers;
401 status = boardobjgrpconstruct_e32(g, &pclk_freq_controllers->super);
402 if (status) {
403 nvgpu_err(g,
404 "error creating boardobjgrp for clk FCT, status - 0x%x",
405 status);
406 goto done;
407 }
408
409 pboardobjgrp = &g->clk_pmu.clk_freq_controllers.super.super;
410
411 pboardobjgrp->pmudatainit = _clk_freq_controllers_pmudatainit;
412 pboardobjgrp->pmudatainstget =
413 _clk_freq_controller_devgrp_pmudata_instget;
414 pboardobjgrp->pmustatusinstget = NULL;
415
416 /* Initialize mask to zero.*/
417 boardobjgrpmask_e32_init(&pclk_freq_controllers->freq_ctrl_load_mask,
418 NULL);
419
420 BOARDOBJGRP_PMU_CONSTRUCT(pboardobjgrp, CLK, CLK_FREQ_CONTROLLER);
421
422 status = BOARDOBJGRP_PMU_CMD_GRP_SET_CONSTRUCT(g, pboardobjgrp,
423 clk, CLK, clk_freq_controller, CLK_FREQ_CONTROLLER);
424 if (status) {
425 nvgpu_err(g,
426 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
427 status);
428 goto done;
429 }
430
431 status = clk_get_freq_controller_table(g, pclk_freq_controllers);
432 if (status) {
433 nvgpu_err(g, "error reading freq controller table - 0x%x",
434 status);
435 goto done;
436 }
437
438 BOARDOBJGRP_FOR_EACH(&(pclk_freq_controllers->super.super),
439 struct clk_freq_controller *, pclkfreqctrl, i) {
440 pfll = NULL;
441 j = 0;
442 BOARDOBJGRP_FOR_EACH(&(pfllobjs->super.super),
443 struct fll_device *, pfll, j) {
444 if (pclkfreqctrl->controller_id == pfll->id) {
445 pfll->freq_ctrl_idx = i;
446 break;
447 }
448 }
449 boardobjgrpmask_bitset(&pclk_freq_controllers->
450 freq_ctrl_load_mask.super, i);
451 }
452done:
453 gk20a_dbg_info(" done status %x", status);
454 return status;
455}