summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/pstate/pstate.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/nvgpu/pstate/pstate.c')
-rw-r--r--drivers/gpu/nvgpu/pstate/pstate.c434
1 files changed, 434 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/pstate/pstate.c b/drivers/gpu/nvgpu/pstate/pstate.c
new file mode 100644
index 00000000..e164cc83
--- /dev/null
+++ b/drivers/gpu/nvgpu/pstate/pstate.c
@@ -0,0 +1,434 @@
1/*
2 * general p state infrastructure
3 *
4 * Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 */
24
25#include <nvgpu/bios.h>
26
27#include "gk20a/gk20a.h"
28#include "clk/clk.h"
29#include "perf/perf.h"
30#include "pmgr/pmgr.h"
31#include "pstate/pstate.h"
32#include "therm/thrm.h"
33
34static int pstate_sw_setup(struct gk20a *g);
35
36void gk20a_deinit_pstate_support(struct gk20a *g)
37{
38 if (g->ops.clk.mclk_deinit)
39 g->ops.clk.mclk_deinit(g);
40
41 nvgpu_mutex_destroy(&g->perf_pmu.pstatesobjs.pstate_mutex);
42}
43
44/*sw setup for pstate components*/
45int gk20a_init_pstate_support(struct gk20a *g)
46{
47 u32 err;
48
49 gk20a_dbg_fn("");
50
51 err = volt_rail_sw_setup(g);
52 if (err)
53 return err;
54
55 err = volt_dev_sw_setup(g);
56 if (err)
57 return err;
58
59 err = volt_policy_sw_setup(g);
60 if (err)
61 return err;
62
63 err = clk_vin_sw_setup(g);
64 if (err)
65 return err;
66
67 err = clk_fll_sw_setup(g);
68 if (err)
69 return err;
70
71 err = therm_domain_sw_setup(g);
72 if (err)
73 return err;
74
75 err = vfe_var_sw_setup(g);
76 if (err)
77 return err;
78
79 err = vfe_equ_sw_setup(g);
80 if (err)
81 return err;
82
83 err = clk_domain_sw_setup(g);
84 if (err)
85 return err;
86
87 err = clk_vf_point_sw_setup(g);
88 if (err)
89 return err;
90
91 err = clk_prog_sw_setup(g);
92 if (err)
93 return err;
94
95 err = pstate_sw_setup(g);
96 if (err)
97 return err;
98
99 err = pmgr_domain_sw_setup(g);
100 if (err)
101 return err;
102
103 err = clk_freq_controller_sw_setup(g);
104 if (err)
105 return err;
106
107 err = nvgpu_lpwr_pg_setup(g);
108
109 return err;
110}
111
112/*sw setup for pstate components*/
113int gk20a_init_pstate_pmu_support(struct gk20a *g)
114{
115 u32 err;
116
117 gk20a_dbg_fn("");
118
119 if (g->ops.clk.mclk_init) {
120 err = g->ops.clk.mclk_init(g);
121 if (err) {
122 nvgpu_err(g, "failed to set mclk");
123 /* Indicate error and continue */
124 }
125 }
126
127 err = volt_rail_pmu_setup(g);
128 if (err)
129 return err;
130
131 err = volt_dev_pmu_setup(g);
132 if (err)
133 return err;
134
135 err = volt_policy_pmu_setup(g);
136 if (err)
137 return err;
138
139 err = volt_pmu_send_load_cmd_to_pmu(g);
140 if (err) {
141 nvgpu_err(g,
142 "Failed to send VOLT LOAD CMD to PMU: status = 0x%08x.",
143 err);
144 return err;
145 }
146
147 err = therm_domain_pmu_setup(g);
148 if (err)
149 return err;
150
151 err = vfe_var_pmu_setup(g);
152 if (err)
153 return err;
154
155 err = vfe_equ_pmu_setup(g);
156 if (err)
157 return err;
158
159 err = clk_domain_pmu_setup(g);
160 if (err)
161 return err;
162
163 err = clk_prog_pmu_setup(g);
164 if (err)
165 return err;
166
167 err = clk_vin_pmu_setup(g);
168 if (err)
169 return err;
170
171 err = clk_fll_pmu_setup(g);
172 if (err)
173 return err;
174
175 err = clk_vf_point_pmu_setup(g);
176 if (err)
177 return err;
178
179 err = clk_freq_controller_pmu_setup(g);
180 if (err)
181 return err;
182
183 err = clk_pmu_vin_load(g);
184 if (err)
185 return err;
186
187 err = perf_pmu_vfe_load(g);
188 if (err)
189 return err;
190
191 err = pmgr_domain_pmu_setup(g);
192 return err;
193}
194
195static int pstate_construct_super(struct gk20a *g, struct boardobj **ppboardobj,
196 u16 size, void *args)
197{
198 struct pstate *ptmppstate = (struct pstate *)args;
199 struct pstate *pstate;
200 int err;
201
202 err = boardobj_construct_super(g, ppboardobj, size, args);
203 if (err)
204 return err;
205
206 pstate = (struct pstate *)*ppboardobj;
207
208 pstate->num = ptmppstate->num;
209 pstate->clklist = ptmppstate->clklist;
210 pstate->lpwr_entry_idx = ptmppstate->lpwr_entry_idx;
211
212 return 0;
213}
214
215static int pstate_construct_3x(struct gk20a *g, struct boardobj **ppboardobj,
216 u16 size, void *args)
217{
218 struct boardobj *ptmpobj = (struct boardobj *)args;
219
220 ptmpobj->type_mask |= BIT(CTRL_PERF_PSTATE_TYPE_3X);
221 return pstate_construct_super(g, ppboardobj, size, args);
222}
223
224static struct pstate *pstate_construct(struct gk20a *g, void *args)
225{
226 struct pstate *pstate = NULL;
227 struct pstate *tmp = (struct pstate *)args;
228
229 if ((tmp->super.type != CTRL_PERF_PSTATE_TYPE_3X) ||
230 (pstate_construct_3x(g, (struct boardobj **)&pstate,
231 sizeof(struct pstate), args)))
232 nvgpu_err(g,
233 "error constructing pstate num=%u", tmp->num);
234
235 return pstate;
236}
237
238static int pstate_insert(struct gk20a *g, struct pstate *pstate, int index)
239{
240 struct pstates *pstates = &(g->perf_pmu.pstatesobjs);
241 int err;
242
243 err = boardobjgrp_objinsert(&pstates->super.super,
244 (struct boardobj *)pstate, index);
245 if (err) {
246 nvgpu_err(g,
247 "error adding pstate boardobj %d", index);
248 return err;
249 }
250
251 pstates->num_levels++;
252
253 return err;
254}
255
256static int parse_pstate_entry_5x(struct gk20a *g,
257 struct vbios_pstate_header_5x *hdr,
258 struct vbios_pstate_entry_5x *entry,
259 struct pstate *pstate)
260{
261 u8 *p = (u8 *)entry;
262 u32 clkidx;
263
264 p += hdr->base_entry_size;
265
266 memset(pstate, 0, sizeof(struct pstate));
267 pstate->super.type = CTRL_PERF_PSTATE_TYPE_3X;
268 pstate->num = 0x0F - entry->pstate_level;
269 pstate->clklist.num_info = hdr->clock_entry_count;
270 pstate->lpwr_entry_idx = entry->lpwr_entry_idx;
271
272 gk20a_dbg_info("pstate P%u", pstate->num);
273
274 for (clkidx = 0; clkidx < hdr->clock_entry_count; clkidx++) {
275 struct clk_set_info *pclksetinfo;
276 struct vbios_pstate_entry_clock_5x *clk_entry;
277 struct clk_domain *clk_domain;
278
279 clk_domain = (struct clk_domain *)BOARDOBJGRP_OBJ_GET_BY_IDX(
280 &g->clk_pmu.clk_domainobjs.super.super, clkidx);
281
282 pclksetinfo = &pstate->clklist.clksetinfo[clkidx];
283 clk_entry = (struct vbios_pstate_entry_clock_5x *)p;
284
285 pclksetinfo->clkwhich = clk_domain->domain;
286 pclksetinfo->nominal_mhz =
287 BIOS_GET_FIELD(clk_entry->param0,
288 VBIOS_PSTATE_5X_CLOCK_PROG_PARAM0_NOM_FREQ_MHZ);
289 pclksetinfo->min_mhz =
290 BIOS_GET_FIELD(clk_entry->param1,
291 VBIOS_PSTATE_5X_CLOCK_PROG_PARAM1_MIN_FREQ_MHZ);
292 pclksetinfo->max_mhz =
293 BIOS_GET_FIELD(clk_entry->param1,
294 VBIOS_PSTATE_5X_CLOCK_PROG_PARAM1_MAX_FREQ_MHZ);
295
296 gk20a_dbg_info(
297 "clk_domain=%u nominal_mhz=%u min_mhz=%u max_mhz=%u",
298 pclksetinfo->clkwhich, pclksetinfo->nominal_mhz,
299 pclksetinfo->min_mhz, pclksetinfo->max_mhz);
300
301 p += hdr->clock_entry_size;
302 }
303
304 return 0;
305}
306
307static int parse_pstate_table_5x(struct gk20a *g,
308 struct vbios_pstate_header_5x *hdr)
309{
310 struct pstate _pstate, *pstate;
311 struct vbios_pstate_entry_5x *entry;
312 u32 entry_size;
313 u8 i;
314 u8 *p = (u8 *)hdr;
315 int err = 0;
316
317 if ((hdr->header_size != VBIOS_PSTATE_HEADER_5X_SIZE_10) ||
318 (hdr->base_entry_count == 0) ||
319 ((hdr->base_entry_size != VBIOS_PSTATE_BASE_ENTRY_5X_SIZE_2) &&
320 (hdr->base_entry_size != VBIOS_PSTATE_BASE_ENTRY_5X_SIZE_3)) ||
321 (hdr->clock_entry_size != VBIOS_PSTATE_CLOCK_ENTRY_5X_SIZE_6) ||
322 (hdr->clock_entry_count > CLK_SET_INFO_MAX_SIZE))
323 return -EINVAL;
324
325 p += hdr->header_size;
326
327 entry_size = hdr->base_entry_size +
328 hdr->clock_entry_count * hdr->clock_entry_size;
329
330 for (i = 0; i < hdr->base_entry_count; i++, p += entry_size) {
331 entry = (struct vbios_pstate_entry_5x *)p;
332
333 if (entry->pstate_level == VBIOS_PERFLEVEL_SKIP_ENTRY)
334 continue;
335
336 err = parse_pstate_entry_5x(g, hdr, entry, &_pstate);
337 if (err)
338 goto done;
339
340 pstate = pstate_construct(g, &_pstate);
341 if (!pstate)
342 goto done;
343
344 err = pstate_insert(g, pstate, i);
345 if (err)
346 goto done;
347 }
348
349done:
350 return err;
351}
352
353static int pstate_sw_setup(struct gk20a *g)
354{
355 struct vbios_pstate_header_5x *hdr = NULL;
356 int err = 0;
357
358 gk20a_dbg_fn("");
359
360 nvgpu_cond_init(&g->perf_pmu.pstatesobjs.pstate_notifier_wq);
361
362 err = nvgpu_mutex_init(&g->perf_pmu.pstatesobjs.pstate_mutex);
363 if (err)
364 return err;
365
366 err = boardobjgrpconstruct_e32(g, &g->perf_pmu.pstatesobjs.super);
367 if (err) {
368 nvgpu_err(g,
369 "error creating boardobjgrp for pstates, err=%d",
370 err);
371 goto done;
372 }
373
374 hdr = (struct vbios_pstate_header_5x *)
375 nvgpu_bios_get_perf_table_ptrs(g,
376 g->bios.perf_token, PERFORMANCE_TABLE);
377
378 if (!hdr) {
379 nvgpu_err(g, "performance table not found");
380 err = -EINVAL;
381 goto done;
382 }
383
384 if (hdr->version != VBIOS_PSTATE_TABLE_VERSION_5X) {
385 nvgpu_err(g, "unknown/unsupported clocks table version=0x%02x",
386 hdr->version);
387 err = -EINVAL;
388 goto done;
389 }
390
391 err = parse_pstate_table_5x(g, hdr);
392done:
393 if (err)
394 nvgpu_mutex_destroy(&g->perf_pmu.pstatesobjs.pstate_mutex);
395 return err;
396}
397
398struct pstate *pstate_find(struct gk20a *g, u32 num)
399{
400 struct pstates *pstates = &(g->perf_pmu.pstatesobjs);
401 struct pstate *pstate;
402 u8 i;
403
404 gk20a_dbg_info("pstates = %p", pstates);
405
406 BOARDOBJGRP_FOR_EACH(&pstates->super.super,
407 struct pstate *, pstate, i) {
408 gk20a_dbg_info("pstate=%p num=%u (looking for num=%u)",
409 pstate, pstate->num, num);
410 if (pstate->num == num)
411 return pstate;
412 }
413 return NULL;
414}
415
416struct clk_set_info *pstate_get_clk_set_info(struct gk20a *g,
417 u32 pstate_num, enum nv_pmu_clk_clkwhich clkwhich)
418{
419 struct pstate *pstate = pstate_find(g, pstate_num);
420 struct clk_set_info *info;
421 u32 clkidx;
422
423 gk20a_dbg_info("pstate = %p", pstate);
424
425 if (!pstate)
426 return NULL;
427
428 for (clkidx = 0; clkidx < pstate->clklist.num_info; clkidx++) {
429 info = &pstate->clklist.clksetinfo[clkidx];
430 if (info->clkwhich == clkwhich)
431 return info;
432 }
433 return NULL;
434}