diff options
Diffstat (limited to 'include/pstate/pstate.c')
-rw-r--r-- | include/pstate/pstate.c | 488 |
1 files changed, 0 insertions, 488 deletions
diff --git a/include/pstate/pstate.c b/include/pstate/pstate.c deleted file mode 100644 index c1f696a..0000000 --- a/include/pstate/pstate.c +++ /dev/null | |||
@@ -1,488 +0,0 @@ | |||
1 | /* | ||
2 | * general p state infrastructure | ||
3 | * | ||
4 | * Copyright (c) 2016-2018, 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 | #include <nvgpu/gk20a.h> | ||
27 | |||
28 | #include "clk/clk.h" | ||
29 | #include "pmu_perf/pmu_perf.h" | ||
30 | #include "pmgr/pmgr.h" | ||
31 | #include "pstate/pstate.h" | ||
32 | #include "therm/thrm.h" | ||
33 | |||
34 | static int pstate_sw_setup(struct gk20a *g); | ||
35 | |||
36 | void gk20a_deinit_pstate_support(struct gk20a *g) | ||
37 | { | ||
38 | if (g->ops.clk.mclk_deinit) { | ||
39 | g->ops.clk.mclk_deinit(g); | ||
40 | } | ||
41 | |||
42 | nvgpu_mutex_destroy(&g->perf_pmu.pstatesobjs.pstate_mutex); | ||
43 | } | ||
44 | |||
45 | /*sw setup for pstate components*/ | ||
46 | int gk20a_init_pstate_support(struct gk20a *g) | ||
47 | { | ||
48 | int err; | ||
49 | |||
50 | nvgpu_log_fn(g, " "); | ||
51 | |||
52 | err = volt_rail_sw_setup(g); | ||
53 | if (err) { | ||
54 | return err; | ||
55 | } | ||
56 | |||
57 | err = volt_dev_sw_setup(g); | ||
58 | if (err) { | ||
59 | return err; | ||
60 | } | ||
61 | |||
62 | err = volt_policy_sw_setup(g); | ||
63 | if (err) { | ||
64 | return err; | ||
65 | } | ||
66 | |||
67 | err = clk_vin_sw_setup(g); | ||
68 | if (err) { | ||
69 | return err; | ||
70 | } | ||
71 | |||
72 | err = clk_fll_sw_setup(g); | ||
73 | if (err) { | ||
74 | return err; | ||
75 | } | ||
76 | |||
77 | err = therm_domain_sw_setup(g); | ||
78 | if (err) { | ||
79 | return err; | ||
80 | } | ||
81 | |||
82 | err = vfe_var_sw_setup(g); | ||
83 | if (err) { | ||
84 | return err; | ||
85 | } | ||
86 | |||
87 | err = vfe_equ_sw_setup(g); | ||
88 | if (err) { | ||
89 | return err; | ||
90 | } | ||
91 | |||
92 | err = clk_domain_sw_setup(g); | ||
93 | if (err) { | ||
94 | return err; | ||
95 | } | ||
96 | |||
97 | err = clk_vf_point_sw_setup(g); | ||
98 | if (err) { | ||
99 | return err; | ||
100 | } | ||
101 | |||
102 | err = clk_prog_sw_setup(g); | ||
103 | if (err) { | ||
104 | return err; | ||
105 | } | ||
106 | |||
107 | err = pstate_sw_setup(g); | ||
108 | if (err) { | ||
109 | return err; | ||
110 | } | ||
111 | |||
112 | if(g->ops.clk.support_pmgr_domain) { | ||
113 | err = pmgr_domain_sw_setup(g); | ||
114 | if (err) { | ||
115 | return err; | ||
116 | } | ||
117 | } | ||
118 | |||
119 | if (g->ops.clk.support_clk_freq_controller) { | ||
120 | err = clk_freq_controller_sw_setup(g); | ||
121 | if (err) { | ||
122 | return err; | ||
123 | } | ||
124 | } | ||
125 | |||
126 | if(g->ops.clk.support_lpwr_pg) { | ||
127 | err = nvgpu_lpwr_pg_setup(g); | ||
128 | if (err) { | ||
129 | return err; | ||
130 | } | ||
131 | } | ||
132 | |||
133 | return err; | ||
134 | } | ||
135 | |||
136 | /*sw setup for pstate components*/ | ||
137 | int gk20a_init_pstate_pmu_support(struct gk20a *g) | ||
138 | { | ||
139 | u32 err; | ||
140 | |||
141 | nvgpu_log_fn(g, " "); | ||
142 | |||
143 | if (g->ops.clk.mclk_init) { | ||
144 | err = g->ops.clk.mclk_init(g); | ||
145 | if (err) { | ||
146 | nvgpu_err(g, "failed to set mclk"); | ||
147 | /* Indicate error and continue */ | ||
148 | } | ||
149 | } | ||
150 | |||
151 | err = volt_rail_pmu_setup(g); | ||
152 | if (err) { | ||
153 | return err; | ||
154 | } | ||
155 | |||
156 | err = volt_dev_pmu_setup(g); | ||
157 | if (err) { | ||
158 | return err; | ||
159 | } | ||
160 | |||
161 | err = volt_policy_pmu_setup(g); | ||
162 | if (err) { | ||
163 | return err; | ||
164 | } | ||
165 | |||
166 | err = g->ops.pmu_ver.volt.volt_send_load_cmd_to_pmu(g); | ||
167 | if (err) { | ||
168 | nvgpu_err(g, | ||
169 | "Failed to send VOLT LOAD CMD to PMU: status = 0x%08x.", | ||
170 | err); | ||
171 | return err; | ||
172 | } | ||
173 | |||
174 | err = therm_domain_pmu_setup(g); | ||
175 | if (err) { | ||
176 | return err; | ||
177 | } | ||
178 | |||
179 | err = vfe_var_pmu_setup(g); | ||
180 | if (err) { | ||
181 | return err; | ||
182 | } | ||
183 | |||
184 | err = vfe_equ_pmu_setup(g); | ||
185 | if (err) { | ||
186 | return err; | ||
187 | } | ||
188 | |||
189 | err = clk_domain_pmu_setup(g); | ||
190 | if (err) { | ||
191 | return err; | ||
192 | } | ||
193 | |||
194 | err = clk_prog_pmu_setup(g); | ||
195 | if (err) { | ||
196 | return err; | ||
197 | } | ||
198 | |||
199 | err = clk_vin_pmu_setup(g); | ||
200 | if (err) { | ||
201 | return err; | ||
202 | } | ||
203 | |||
204 | err = clk_fll_pmu_setup(g); | ||
205 | if (err) { | ||
206 | return err; | ||
207 | } | ||
208 | |||
209 | err = clk_vf_point_pmu_setup(g); | ||
210 | if (err) { | ||
211 | return err; | ||
212 | } | ||
213 | |||
214 | if (g->ops.clk.support_clk_freq_controller) { | ||
215 | err = clk_freq_controller_pmu_setup(g); | ||
216 | if (err) { | ||
217 | return err; | ||
218 | } | ||
219 | } | ||
220 | err = clk_pmu_vin_load(g); | ||
221 | if (err) { | ||
222 | return err; | ||
223 | } | ||
224 | |||
225 | err = g->ops.clk.perf_pmu_vfe_load(g); | ||
226 | if (err) { | ||
227 | return err; | ||
228 | } | ||
229 | |||
230 | if (g->ops.clk.support_pmgr_domain) { | ||
231 | err = pmgr_domain_pmu_setup(g); | ||
232 | } | ||
233 | |||
234 | return err; | ||
235 | } | ||
236 | |||
237 | static int pstate_construct_super(struct gk20a *g, struct boardobj **ppboardobj, | ||
238 | u16 size, void *args) | ||
239 | { | ||
240 | struct pstate *ptmppstate = (struct pstate *)args; | ||
241 | struct pstate *pstate; | ||
242 | int err; | ||
243 | |||
244 | err = boardobj_construct_super(g, ppboardobj, size, args); | ||
245 | if (err) { | ||
246 | return err; | ||
247 | } | ||
248 | |||
249 | pstate = (struct pstate *)*ppboardobj; | ||
250 | |||
251 | pstate->num = ptmppstate->num; | ||
252 | pstate->clklist = ptmppstate->clklist; | ||
253 | pstate->lpwr_entry_idx = ptmppstate->lpwr_entry_idx; | ||
254 | |||
255 | return 0; | ||
256 | } | ||
257 | |||
258 | static int pstate_construct_3x(struct gk20a *g, struct boardobj **ppboardobj, | ||
259 | u16 size, void *args) | ||
260 | { | ||
261 | struct boardobj *ptmpobj = (struct boardobj *)args; | ||
262 | |||
263 | ptmpobj->type_mask |= BIT(CTRL_PERF_PSTATE_TYPE_3X); | ||
264 | return pstate_construct_super(g, ppboardobj, size, args); | ||
265 | } | ||
266 | |||
267 | static struct pstate *pstate_construct(struct gk20a *g, void *args) | ||
268 | { | ||
269 | struct pstate *pstate = NULL; | ||
270 | struct pstate *tmp = (struct pstate *)args; | ||
271 | |||
272 | if ((tmp->super.type != CTRL_PERF_PSTATE_TYPE_3X) || | ||
273 | (pstate_construct_3x(g, (struct boardobj **)&pstate, | ||
274 | sizeof(struct pstate), args))) { | ||
275 | nvgpu_err(g, | ||
276 | "error constructing pstate num=%u", tmp->num); | ||
277 | } | ||
278 | |||
279 | return pstate; | ||
280 | } | ||
281 | |||
282 | static int pstate_insert(struct gk20a *g, struct pstate *pstate, int index) | ||
283 | { | ||
284 | struct pstates *pstates = &(g->perf_pmu.pstatesobjs); | ||
285 | int err; | ||
286 | |||
287 | err = boardobjgrp_objinsert(&pstates->super.super, | ||
288 | (struct boardobj *)pstate, index); | ||
289 | if (err) { | ||
290 | nvgpu_err(g, | ||
291 | "error adding pstate boardobj %d", index); | ||
292 | return err; | ||
293 | } | ||
294 | |||
295 | pstates->num_levels++; | ||
296 | |||
297 | return err; | ||
298 | } | ||
299 | |||
300 | static int parse_pstate_entry_5x(struct gk20a *g, | ||
301 | struct vbios_pstate_header_5x *hdr, | ||
302 | struct vbios_pstate_entry_5x *entry, | ||
303 | struct pstate *pstate) | ||
304 | { | ||
305 | u8 *p = (u8 *)entry; | ||
306 | u32 clkidx; | ||
307 | |||
308 | p += hdr->base_entry_size; | ||
309 | |||
310 | memset(pstate, 0, sizeof(struct pstate)); | ||
311 | pstate->super.type = CTRL_PERF_PSTATE_TYPE_3X; | ||
312 | pstate->num = 0x0F - entry->pstate_level; | ||
313 | pstate->clklist.num_info = hdr->clock_entry_count; | ||
314 | pstate->lpwr_entry_idx = entry->lpwr_entry_idx; | ||
315 | |||
316 | nvgpu_log_info(g, "pstate P%u", pstate->num); | ||
317 | |||
318 | for (clkidx = 0; clkidx < hdr->clock_entry_count; clkidx++) { | ||
319 | struct clk_set_info *pclksetinfo; | ||
320 | struct vbios_pstate_entry_clock_5x *clk_entry; | ||
321 | struct clk_domain *clk_domain; | ||
322 | |||
323 | clk_domain = (struct clk_domain *)BOARDOBJGRP_OBJ_GET_BY_IDX( | ||
324 | &g->clk_pmu.clk_domainobjs.super.super, clkidx); | ||
325 | |||
326 | pclksetinfo = &pstate->clklist.clksetinfo[clkidx]; | ||
327 | clk_entry = (struct vbios_pstate_entry_clock_5x *)p; | ||
328 | |||
329 | pclksetinfo->clkwhich = clk_domain->domain; | ||
330 | pclksetinfo->nominal_mhz = | ||
331 | BIOS_GET_FIELD(clk_entry->param0, | ||
332 | VBIOS_PSTATE_5X_CLOCK_PROG_PARAM0_NOM_FREQ_MHZ); | ||
333 | pclksetinfo->min_mhz = | ||
334 | BIOS_GET_FIELD(clk_entry->param1, | ||
335 | VBIOS_PSTATE_5X_CLOCK_PROG_PARAM1_MIN_FREQ_MHZ); | ||
336 | pclksetinfo->max_mhz = | ||
337 | BIOS_GET_FIELD(clk_entry->param1, | ||
338 | VBIOS_PSTATE_5X_CLOCK_PROG_PARAM1_MAX_FREQ_MHZ); | ||
339 | |||
340 | nvgpu_log_info(g, | ||
341 | "clk_domain=%u nominal_mhz=%u min_mhz=%u max_mhz=%u", | ||
342 | pclksetinfo->clkwhich, pclksetinfo->nominal_mhz, | ||
343 | pclksetinfo->min_mhz, pclksetinfo->max_mhz); | ||
344 | |||
345 | p += hdr->clock_entry_size; | ||
346 | } | ||
347 | |||
348 | return 0; | ||
349 | } | ||
350 | |||
351 | static int parse_pstate_table_5x(struct gk20a *g, | ||
352 | struct vbios_pstate_header_5x *hdr) | ||
353 | { | ||
354 | struct pstate _pstate, *pstate; | ||
355 | struct vbios_pstate_entry_5x *entry; | ||
356 | u32 entry_size; | ||
357 | u8 i; | ||
358 | u8 *p = (u8 *)hdr; | ||
359 | int err = 0; | ||
360 | |||
361 | if ((hdr->header_size != VBIOS_PSTATE_HEADER_5X_SIZE_10) || | ||
362 | (hdr->base_entry_count == 0) || | ||
363 | ((hdr->base_entry_size != VBIOS_PSTATE_BASE_ENTRY_5X_SIZE_2) && | ||
364 | (hdr->base_entry_size != VBIOS_PSTATE_BASE_ENTRY_5X_SIZE_3)) || | ||
365 | (hdr->clock_entry_size != VBIOS_PSTATE_CLOCK_ENTRY_5X_SIZE_6) || | ||
366 | (hdr->clock_entry_count > CLK_SET_INFO_MAX_SIZE)) { | ||
367 | return -EINVAL; | ||
368 | } | ||
369 | |||
370 | p += hdr->header_size; | ||
371 | |||
372 | entry_size = hdr->base_entry_size + | ||
373 | hdr->clock_entry_count * hdr->clock_entry_size; | ||
374 | |||
375 | for (i = 0; i < hdr->base_entry_count; i++, p += entry_size) { | ||
376 | entry = (struct vbios_pstate_entry_5x *)p; | ||
377 | |||
378 | if (entry->pstate_level == VBIOS_PERFLEVEL_SKIP_ENTRY) { | ||
379 | continue; | ||
380 | } | ||
381 | |||
382 | err = parse_pstate_entry_5x(g, hdr, entry, &_pstate); | ||
383 | if (err) { | ||
384 | goto done; | ||
385 | } | ||
386 | |||
387 | pstate = pstate_construct(g, &_pstate); | ||
388 | if (!pstate) { | ||
389 | goto done; | ||
390 | } | ||
391 | |||
392 | err = pstate_insert(g, pstate, i); | ||
393 | if (err) { | ||
394 | goto done; | ||
395 | } | ||
396 | } | ||
397 | |||
398 | done: | ||
399 | return err; | ||
400 | } | ||
401 | |||
402 | static int pstate_sw_setup(struct gk20a *g) | ||
403 | { | ||
404 | struct vbios_pstate_header_5x *hdr = NULL; | ||
405 | int err = 0; | ||
406 | |||
407 | nvgpu_log_fn(g, " "); | ||
408 | |||
409 | nvgpu_cond_init(&g->perf_pmu.pstatesobjs.pstate_notifier_wq); | ||
410 | |||
411 | err = nvgpu_mutex_init(&g->perf_pmu.pstatesobjs.pstate_mutex); | ||
412 | if (err) { | ||
413 | return err; | ||
414 | } | ||
415 | |||
416 | err = boardobjgrpconstruct_e32(g, &g->perf_pmu.pstatesobjs.super); | ||
417 | if (err) { | ||
418 | nvgpu_err(g, | ||
419 | "error creating boardobjgrp for pstates, err=%d", | ||
420 | err); | ||
421 | goto done; | ||
422 | } | ||
423 | |||
424 | hdr = (struct vbios_pstate_header_5x *) | ||
425 | nvgpu_bios_get_perf_table_ptrs(g, | ||
426 | g->bios.perf_token, PERFORMANCE_TABLE); | ||
427 | |||
428 | if (!hdr) { | ||
429 | nvgpu_err(g, "performance table not found"); | ||
430 | err = -EINVAL; | ||
431 | goto done; | ||
432 | } | ||
433 | |||
434 | if (hdr->version != VBIOS_PSTATE_TABLE_VERSION_5X) { | ||
435 | nvgpu_err(g, "unknown/unsupported clocks table version=0x%02x", | ||
436 | hdr->version); | ||
437 | err = -EINVAL; | ||
438 | goto done; | ||
439 | } | ||
440 | |||
441 | err = parse_pstate_table_5x(g, hdr); | ||
442 | done: | ||
443 | if (err) { | ||
444 | nvgpu_mutex_destroy(&g->perf_pmu.pstatesobjs.pstate_mutex); | ||
445 | } | ||
446 | return err; | ||
447 | } | ||
448 | |||
449 | struct pstate *pstate_find(struct gk20a *g, u32 num) | ||
450 | { | ||
451 | struct pstates *pstates = &(g->perf_pmu.pstatesobjs); | ||
452 | struct pstate *pstate; | ||
453 | u8 i; | ||
454 | |||
455 | nvgpu_log_info(g, "pstates = %p", pstates); | ||
456 | |||
457 | BOARDOBJGRP_FOR_EACH(&pstates->super.super, | ||
458 | struct pstate *, pstate, i) { | ||
459 | nvgpu_log_info(g, "pstate=%p num=%u (looking for num=%u)", | ||
460 | pstate, pstate->num, num); | ||
461 | if (pstate->num == num) { | ||
462 | return pstate; | ||
463 | } | ||
464 | } | ||
465 | return NULL; | ||
466 | } | ||
467 | |||
468 | struct clk_set_info *pstate_get_clk_set_info(struct gk20a *g, | ||
469 | u32 pstate_num, enum nv_pmu_clk_clkwhich clkwhich) | ||
470 | { | ||
471 | struct pstate *pstate = pstate_find(g, pstate_num); | ||
472 | struct clk_set_info *info; | ||
473 | u32 clkidx; | ||
474 | |||
475 | nvgpu_log_info(g, "pstate = %p", pstate); | ||
476 | |||
477 | if (!pstate) { | ||
478 | return NULL; | ||
479 | } | ||
480 | |||
481 | for (clkidx = 0; clkidx < pstate->clklist.num_info; clkidx++) { | ||
482 | info = &pstate->clklist.clksetinfo[clkidx]; | ||
483 | if (info->clkwhich == clkwhich) { | ||
484 | return info; | ||
485 | } | ||
486 | } | ||
487 | return NULL; | ||
488 | } | ||