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.c407
1 files changed, 407 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..82e809bb
--- /dev/null
+++ b/drivers/gpu/nvgpu/pstate/pstate.c
@@ -0,0 +1,407 @@
1/*
2 * general p state infrastructure
3 *
4 * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 */
15
16#include "gk20a/gk20a.h"
17#include "clk/clk.h"
18#include "perf/perf.h"
19#include "pmgr/pmgr.h"
20#include "include/bios.h"
21#include "pstate/pstate.h"
22#include "therm/thrm.h"
23
24static int pstate_sw_setup(struct gk20a *g);
25
26/*sw setup for pstate components*/
27int gk20a_init_pstate_support(struct gk20a *g)
28{
29 u32 err;
30
31 gk20a_dbg_fn("");
32
33 err = volt_rail_sw_setup(g);
34 if (err)
35 return err;
36
37 err = volt_dev_sw_setup(g);
38 if (err)
39 return err;
40
41 err = volt_policy_sw_setup(g);
42 if (err)
43 return err;
44
45 err = clk_vin_sw_setup(g);
46 if (err)
47 return err;
48
49 err = clk_fll_sw_setup(g);
50 if (err)
51 return err;
52
53 err = therm_domain_sw_setup(g);
54 if (err)
55 return err;
56
57 err = vfe_var_sw_setup(g);
58 if (err)
59 return err;
60
61 err = vfe_equ_sw_setup(g);
62 if (err)
63 return err;
64
65 err = clk_domain_sw_setup(g);
66 if (err)
67 return err;
68
69 err = clk_vf_point_sw_setup(g);
70 if (err)
71 return err;
72
73 err = clk_prog_sw_setup(g);
74 if (err)
75 return err;
76
77 err = pstate_sw_setup(g);
78 if (err)
79 return err;
80
81 err = pmgr_domain_sw_setup(g);
82 if (err)
83 return err;
84
85 err = clk_freq_controller_sw_setup(g);
86 if (err)
87 return err;
88
89 err = nvgpu_lpwr_pg_setup(g);
90
91 return err;
92}
93
94/*sw setup for pstate components*/
95int gk20a_init_pstate_pmu_support(struct gk20a *g)
96{
97 u32 err;
98
99 gk20a_dbg_fn("");
100
101 err = volt_rail_pmu_setup(g);
102 if (err)
103 return err;
104
105 err = volt_dev_pmu_setup(g);
106 if (err)
107 return err;
108
109 err = volt_policy_pmu_setup(g);
110 if (err)
111 return err;
112
113 err = volt_pmu_send_load_cmd_to_pmu(g);
114 if (err) {
115 gk20a_err(dev_from_gk20a(g),
116 "Failed to send VOLT LOAD CMD to PMU: status = 0x%08x.",
117 err);
118 return err;
119 }
120
121 err = therm_domain_pmu_setup(g);
122 if (err)
123 return err;
124
125 err = vfe_var_pmu_setup(g);
126 if (err)
127 return err;
128
129 err = vfe_equ_pmu_setup(g);
130 if (err)
131 return err;
132
133 err = clk_domain_pmu_setup(g);
134 if (err)
135 return err;
136
137 err = clk_prog_pmu_setup(g);
138 if (err)
139 return err;
140
141 err = clk_vin_pmu_setup(g);
142 if (err)
143 return err;
144
145 err = clk_fll_pmu_setup(g);
146 if (err)
147 return err;
148
149 err = clk_vf_point_pmu_setup(g);
150 if (err)
151 return err;
152
153 err = clk_freq_controller_pmu_setup(g);
154 if (err)
155 return err;
156
157 err = clk_pmu_vin_load(g);
158 if (err)
159 return err;
160
161 err = perf_pmu_vfe_load(g);
162 if (err)
163 return err;
164
165 err = pmgr_domain_pmu_setup(g);
166 return err;
167}
168
169int pstate_construct_super(struct gk20a *g, struct boardobj **ppboardobj,
170 u16 size, void *args)
171{
172 struct pstate *ptmppstate = (struct pstate *)args;
173 struct pstate *pstate;
174 int err;
175
176 err = boardobj_construct_super(g, ppboardobj, size, args);
177 if (err)
178 return err;
179
180 pstate = (struct pstate *)*ppboardobj;
181
182 pstate->num = ptmppstate->num;
183 pstate->clklist = ptmppstate->clklist;
184 pstate->lpwr_entry_idx = ptmppstate->lpwr_entry_idx;
185
186 return 0;
187}
188
189int pstate_construct_3x(struct gk20a *g, struct boardobj **ppboardobj,
190 u16 size, void *args)
191{
192 struct boardobj *ptmpobj = (struct boardobj *)args;
193
194 ptmpobj->type_mask |= BIT(CTRL_PERF_PSTATE_TYPE_3X);
195 return pstate_construct_super(g, ppboardobj, size, args);
196}
197
198struct pstate *pstate_construct(struct gk20a *g, void *args)
199{
200 struct pstate *pstate = NULL;
201 struct pstate *tmp = (struct pstate *)args;
202
203 if ((tmp->super.type != CTRL_PERF_PSTATE_TYPE_3X) ||
204 (pstate_construct_3x(g, (struct boardobj **)&pstate,
205 sizeof(struct pstate), args)))
206 gk20a_err(dev_from_gk20a(g),
207 "error constructing pstate num=%u", tmp->num);
208
209 return pstate;
210}
211
212int pstate_insert(struct gk20a *g, struct pstate *pstate, int index)
213{
214 struct pstates *pstates = &(g->perf_pmu.pstatesobjs);
215 int err;
216
217 err = boardobjgrp_objinsert(&pstates->super.super,
218 (struct boardobj *)pstate, index);
219 if (err) {
220 gk20a_err(dev_from_gk20a(g),
221 "error adding pstate boardobj %d", index);
222 return err;
223 }
224
225 pstates->num_levels++;
226
227 return err;
228}
229
230static int parse_pstate_entry_5x(struct gk20a *g,
231 struct vbios_pstate_header_5x *hdr,
232 struct vbios_pstate_entry_5x *entry,
233 struct pstate *pstate)
234{
235 u8 *p = (u8 *)entry;
236 u32 clkidx;
237
238 p += hdr->base_entry_size;
239
240 memset(pstate, 0, sizeof(struct pstate));
241 pstate->super.type = CTRL_PERF_PSTATE_TYPE_3X;
242 pstate->num = 0x0F - entry->pstate_level;
243 pstate->clklist.num_info = hdr->clock_entry_count;
244 pstate->lpwr_entry_idx = entry->lpwr_entry_idx;
245
246 gk20a_dbg_info("pstate P%u", pstate->num);
247
248 for (clkidx = 0; clkidx < hdr->clock_entry_count; clkidx++) {
249 struct clk_set_info *pclksetinfo;
250 struct vbios_pstate_entry_clock_5x *clk_entry;
251 struct clk_domain *clk_domain;
252
253 clk_domain = (struct clk_domain *)BOARDOBJGRP_OBJ_GET_BY_IDX(
254 &g->clk_pmu.clk_domainobjs.super.super, clkidx);
255
256 pclksetinfo = &pstate->clklist.clksetinfo[clkidx];
257 clk_entry = (struct vbios_pstate_entry_clock_5x *)p;
258
259 pclksetinfo->clkwhich = clk_domain->domain;
260 pclksetinfo->nominal_mhz =
261 BIOS_GET_FIELD(clk_entry->param0,
262 VBIOS_PSTATE_5X_CLOCK_PROG_PARAM0_NOM_FREQ_MHZ);
263 pclksetinfo->min_mhz =
264 BIOS_GET_FIELD(clk_entry->param1,
265 VBIOS_PSTATE_5X_CLOCK_PROG_PARAM1_MIN_FREQ_MHZ);
266 pclksetinfo->max_mhz =
267 BIOS_GET_FIELD(clk_entry->param1,
268 VBIOS_PSTATE_5X_CLOCK_PROG_PARAM1_MAX_FREQ_MHZ);
269
270 gk20a_dbg_info(
271 "clk_domain=%u nominal_mhz=%u min_mhz=%u max_mhz=%u",
272 pclksetinfo->clkwhich, pclksetinfo->nominal_mhz,
273 pclksetinfo->min_mhz, pclksetinfo->max_mhz);
274
275 p += hdr->clock_entry_size;
276 }
277
278 return 0;
279}
280
281static int parse_pstate_table_5x(struct gk20a *g,
282 struct vbios_pstate_header_5x *hdr)
283{
284 struct pstate _pstate, *pstate = &_pstate;
285 struct vbios_pstate_entry_5x *entry;
286 u32 entry_size;
287 u8 i;
288 u8 *p = (u8 *)hdr;
289 int err = 0;
290
291 if ((hdr->header_size != VBIOS_PSTATE_HEADER_5X_SIZE_10) ||
292 (hdr->base_entry_count == 0) ||
293 ((hdr->base_entry_size != VBIOS_PSTATE_BASE_ENTRY_5X_SIZE_2) &&
294 (hdr->base_entry_size != VBIOS_PSTATE_BASE_ENTRY_5X_SIZE_3)) ||
295 (hdr->clock_entry_size != VBIOS_PSTATE_CLOCK_ENTRY_5X_SIZE_6) ||
296 (hdr->clock_entry_count > CLK_SET_INFO_MAX_SIZE))
297 return -EINVAL;
298
299 p += hdr->header_size;
300
301 entry_size = hdr->base_entry_size +
302 hdr->clock_entry_count * hdr->clock_entry_size;
303
304 for (i = 0; i < hdr->base_entry_count; i++, p += entry_size) {
305 entry = (struct vbios_pstate_entry_5x *)p;
306
307 if (entry->pstate_level == VBIOS_PERFLEVEL_SKIP_ENTRY)
308 continue;
309
310 err = parse_pstate_entry_5x(g, hdr, entry, pstate);
311 if (err)
312 goto done;
313
314 pstate = pstate_construct(g, pstate);
315 if (!pstate)
316 goto done;
317
318 err = pstate_insert(g, pstate, i);
319 if (err)
320 goto done;
321 }
322
323done:
324 return err;
325}
326
327static int pstate_sw_setup(struct gk20a *g)
328{
329 struct vbios_pstate_header_5x *hdr = NULL;
330 int err = 0;
331
332 gk20a_dbg_fn("");
333
334 init_waitqueue_head(&g->perf_pmu.pstatesobjs.pstate_notifier_wq);
335 mutex_init(&g->perf_pmu.pstatesobjs.pstate_mutex);
336
337 err = boardobjgrpconstruct_e32(&g->perf_pmu.pstatesobjs.super);
338 if (err) {
339 gk20a_err(dev_from_gk20a(g),
340 "error creating boardobjgrp for pstates, err=%d",
341 err);
342 goto done;
343 }
344
345 if (g->ops.bios.get_perf_table_ptrs) {
346 hdr = (struct vbios_pstate_header_5x *)
347 g->ops.bios.get_perf_table_ptrs(g,
348 g->bios.perf_token, PERFORMANCE_TABLE);
349 }
350
351 if (!hdr) {
352 gk20a_err(dev_from_gk20a(g),
353 "performance table not found");
354 err = -EINVAL;
355 goto done;
356 }
357
358 if (hdr->version != VBIOS_PSTATE_TABLE_VERSION_5X) {
359 gk20a_err(dev_from_gk20a(g),
360 "unknown/unsupported clocks table version=0x%02x",
361 hdr->version);
362 err = -EINVAL;
363 goto done;
364 }
365
366 err = parse_pstate_table_5x(g, hdr);
367done:
368 return err;
369}
370
371struct pstate *pstate_find(struct gk20a *g, u32 num)
372{
373 struct pstates *pstates = &(g->perf_pmu.pstatesobjs);
374 struct pstate *pstate;
375 u8 i;
376
377 gk20a_dbg_info("pstates = %p", pstates);
378
379 BOARDOBJGRP_FOR_EACH(&pstates->super.super,
380 struct pstate *, pstate, i) {
381 gk20a_dbg_info("pstate=%p num=%u (looking for num=%u)",
382 pstate, pstate->num, num);
383 if (pstate->num == num)
384 return pstate;
385 }
386 return NULL;
387}
388
389struct clk_set_info *pstate_get_clk_set_info(struct gk20a *g,
390 u32 pstate_num, enum nv_pmu_clk_clkwhich clkwhich)
391{
392 struct pstate *pstate = pstate_find(g, pstate_num);
393 struct clk_set_info *info;
394 u32 clkidx;
395
396 gk20a_dbg_info("pstate = %p", pstate);
397
398 if (!pstate)
399 return NULL;
400
401 for (clkidx = 0; clkidx < pstate->clklist.num_info; clkidx++) {
402 info = &pstate->clklist.clksetinfo[clkidx];
403 if (info->clkwhich == clkwhich)
404 return info;
405 }
406 return NULL;
407}