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.c454
1 files changed, 454 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..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}