diff options
Diffstat (limited to 'include/clk/clk_vf_point.c')
-rw-r--r-- | include/clk/clk_vf_point.c | 433 |
1 files changed, 433 insertions, 0 deletions
diff --git a/include/clk/clk_vf_point.c b/include/clk/clk_vf_point.c new file mode 100644 index 0000000..96413c8 --- /dev/null +++ b/include/clk/clk_vf_point.c | |||
@@ -0,0 +1,433 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2016-2018, 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/gk20a.h> | ||
24 | |||
25 | #include "clk.h" | ||
26 | #include "clk_vf_point.h" | ||
27 | #include "boardobj/boardobjgrp.h" | ||
28 | #include "boardobj/boardobjgrp_e32.h" | ||
29 | #include "ctrl/ctrlclk.h" | ||
30 | #include "ctrl/ctrlvolt.h" | ||
31 | |||
32 | static int _clk_vf_point_pmudatainit_super(struct gk20a *g, struct boardobj | ||
33 | *board_obj_ptr, struct nv_pmu_boardobj *ppmudata); | ||
34 | |||
35 | static int _clk_vf_points_pmudatainit(struct gk20a *g, | ||
36 | struct boardobjgrp *pboardobjgrp, | ||
37 | struct nv_pmu_boardobjgrp_super *pboardobjgrppmu) | ||
38 | { | ||
39 | u32 status = 0; | ||
40 | |||
41 | status = boardobjgrp_pmudatainit_e32(g, pboardobjgrp, pboardobjgrppmu); | ||
42 | if (status) { | ||
43 | nvgpu_err(g, | ||
44 | "error updating pmu boardobjgrp for clk vfpoint 0x%x", | ||
45 | status); | ||
46 | goto done; | ||
47 | } | ||
48 | |||
49 | done: | ||
50 | return status; | ||
51 | } | ||
52 | |||
53 | static int _clk_vf_points_pmudata_instget(struct gk20a *g, | ||
54 | struct nv_pmu_boardobjgrp *pmuboardobjgrp, | ||
55 | struct nv_pmu_boardobj **ppboardobjpmudata, | ||
56 | u8 idx) | ||
57 | { | ||
58 | struct nv_pmu_clk_clk_vf_point_boardobj_grp_set *pgrp_set = | ||
59 | (struct nv_pmu_clk_clk_vf_point_boardobj_grp_set *) | ||
60 | pmuboardobjgrp; | ||
61 | |||
62 | nvgpu_log_info(g, " "); | ||
63 | |||
64 | /*check whether pmuboardobjgrp has a valid boardobj in index*/ | ||
65 | if (idx >= CTRL_BOARDOBJGRP_E255_MAX_OBJECTS) { | ||
66 | return -EINVAL; | ||
67 | } | ||
68 | |||
69 | *ppboardobjpmudata = (struct nv_pmu_boardobj *) | ||
70 | &pgrp_set->objects[idx].data.board_obj; | ||
71 | nvgpu_log_info(g, " Done"); | ||
72 | return 0; | ||
73 | } | ||
74 | |||
75 | static int _clk_vf_points_pmustatus_instget(struct gk20a *g, | ||
76 | void *pboardobjgrppmu, | ||
77 | struct nv_pmu_boardobj_query **ppboardobjpmustatus, | ||
78 | u8 idx) | ||
79 | { | ||
80 | struct nv_pmu_clk_clk_vf_point_boardobj_grp_get_status *pgrp_get_status = | ||
81 | (struct nv_pmu_clk_clk_vf_point_boardobj_grp_get_status *) | ||
82 | pboardobjgrppmu; | ||
83 | |||
84 | /*check whether pmuboardobjgrp has a valid boardobj in index*/ | ||
85 | if (idx >= CTRL_BOARDOBJGRP_E255_MAX_OBJECTS) { | ||
86 | return -EINVAL; | ||
87 | } | ||
88 | |||
89 | *ppboardobjpmustatus = (struct nv_pmu_boardobj_query *) | ||
90 | &pgrp_get_status->objects[idx].data.board_obj; | ||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | int clk_vf_point_sw_setup(struct gk20a *g) | ||
95 | { | ||
96 | int status; | ||
97 | struct boardobjgrp *pboardobjgrp = NULL; | ||
98 | |||
99 | nvgpu_log_info(g, " "); | ||
100 | |||
101 | status = boardobjgrpconstruct_e255(g, &g->clk_pmu.clk_vf_pointobjs.super); | ||
102 | if (status) { | ||
103 | nvgpu_err(g, | ||
104 | "error creating boardobjgrp for clk vfpoint, status - 0x%x", | ||
105 | status); | ||
106 | goto done; | ||
107 | } | ||
108 | |||
109 | pboardobjgrp = &g->clk_pmu.clk_vf_pointobjs.super.super; | ||
110 | |||
111 | BOARDOBJGRP_PMU_CONSTRUCT(pboardobjgrp, CLK, CLK_VF_POINT); | ||
112 | |||
113 | status = BOARDOBJGRP_PMU_CMD_GRP_SET_CONSTRUCT(g, pboardobjgrp, | ||
114 | clk, CLK, clk_vf_point, CLK_VF_POINT); | ||
115 | if (status) { | ||
116 | nvgpu_err(g, | ||
117 | "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x", | ||
118 | status); | ||
119 | goto done; | ||
120 | } | ||
121 | |||
122 | status = BOARDOBJGRP_PMU_CMD_GRP_GET_STATUS_CONSTRUCT(g, | ||
123 | &g->clk_pmu.clk_vf_pointobjs.super.super, | ||
124 | clk, CLK, clk_vf_point, CLK_VF_POINT); | ||
125 | if (status) { | ||
126 | nvgpu_err(g, | ||
127 | "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x", | ||
128 | status); | ||
129 | goto done; | ||
130 | } | ||
131 | |||
132 | pboardobjgrp->pmudatainit = _clk_vf_points_pmudatainit; | ||
133 | pboardobjgrp->pmudatainstget = _clk_vf_points_pmudata_instget; | ||
134 | pboardobjgrp->pmustatusinstget = _clk_vf_points_pmustatus_instget; | ||
135 | |||
136 | done: | ||
137 | nvgpu_log_info(g, " done status %x", status); | ||
138 | return status; | ||
139 | } | ||
140 | |||
141 | int clk_vf_point_pmu_setup(struct gk20a *g) | ||
142 | { | ||
143 | int status; | ||
144 | struct boardobjgrp *pboardobjgrp = NULL; | ||
145 | |||
146 | nvgpu_log_info(g, " "); | ||
147 | |||
148 | pboardobjgrp = &g->clk_pmu.clk_vf_pointobjs.super.super; | ||
149 | |||
150 | if (!pboardobjgrp->bconstructed) { | ||
151 | return -EINVAL; | ||
152 | } | ||
153 | |||
154 | status = pboardobjgrp->pmuinithandle(g, pboardobjgrp); | ||
155 | |||
156 | nvgpu_log_info(g, "Done"); | ||
157 | return status; | ||
158 | } | ||
159 | |||
160 | static int clk_vf_point_construct_super(struct gk20a *g, | ||
161 | struct boardobj **ppboardobj, | ||
162 | u16 size, void *pargs) | ||
163 | { | ||
164 | struct clk_vf_point *pclkvfpoint; | ||
165 | struct clk_vf_point *ptmpvfpoint = | ||
166 | (struct clk_vf_point *)pargs; | ||
167 | int status = 0; | ||
168 | |||
169 | status = boardobj_construct_super(g, ppboardobj, | ||
170 | size, pargs); | ||
171 | if (status) { | ||
172 | return -EINVAL; | ||
173 | } | ||
174 | |||
175 | pclkvfpoint = (struct clk_vf_point *)*ppboardobj; | ||
176 | |||
177 | pclkvfpoint->super.pmudatainit = | ||
178 | _clk_vf_point_pmudatainit_super; | ||
179 | |||
180 | pclkvfpoint->vfe_equ_idx = ptmpvfpoint->vfe_equ_idx; | ||
181 | pclkvfpoint->volt_rail_idx = ptmpvfpoint->volt_rail_idx; | ||
182 | |||
183 | return status; | ||
184 | } | ||
185 | |||
186 | static int _clk_vf_point_pmudatainit_volt(struct gk20a *g, | ||
187 | struct boardobj *board_obj_ptr, | ||
188 | struct nv_pmu_boardobj *ppmudata) | ||
189 | { | ||
190 | int status = 0; | ||
191 | struct clk_vf_point_volt *pclk_vf_point_volt; | ||
192 | struct nv_pmu_clk_clk_vf_point_volt_boardobj_set *pset; | ||
193 | |||
194 | nvgpu_log_info(g, " "); | ||
195 | |||
196 | status = _clk_vf_point_pmudatainit_super(g, board_obj_ptr, ppmudata); | ||
197 | if (status != 0) { | ||
198 | return status; | ||
199 | } | ||
200 | |||
201 | pclk_vf_point_volt = | ||
202 | (struct clk_vf_point_volt *)board_obj_ptr; | ||
203 | |||
204 | pset = (struct nv_pmu_clk_clk_vf_point_volt_boardobj_set *) | ||
205 | ppmudata; | ||
206 | |||
207 | pset->source_voltage_uv = pclk_vf_point_volt->source_voltage_uv; | ||
208 | pset->freq_delta.data = pclk_vf_point_volt->freq_delta.data; | ||
209 | pset->freq_delta.type = pclk_vf_point_volt->freq_delta.type; | ||
210 | |||
211 | return status; | ||
212 | } | ||
213 | |||
214 | static int _clk_vf_point_pmudatainit_freq(struct gk20a *g, | ||
215 | struct boardobj *board_obj_ptr, | ||
216 | struct nv_pmu_boardobj *ppmudata) | ||
217 | { | ||
218 | int status = 0; | ||
219 | struct clk_vf_point_freq *pclk_vf_point_freq; | ||
220 | struct nv_pmu_clk_clk_vf_point_freq_boardobj_set *pset; | ||
221 | |||
222 | nvgpu_log_info(g, " "); | ||
223 | |||
224 | status = _clk_vf_point_pmudatainit_super(g, board_obj_ptr, ppmudata); | ||
225 | if (status != 0) { | ||
226 | return status; | ||
227 | } | ||
228 | |||
229 | pclk_vf_point_freq = | ||
230 | (struct clk_vf_point_freq *)board_obj_ptr; | ||
231 | |||
232 | pset = (struct nv_pmu_clk_clk_vf_point_freq_boardobj_set *) | ||
233 | ppmudata; | ||
234 | |||
235 | pset->freq_mhz = | ||
236 | clkvfpointfreqmhzget(g, &pclk_vf_point_freq->super); | ||
237 | |||
238 | pset->volt_delta_uv = pclk_vf_point_freq->volt_delta_uv; | ||
239 | |||
240 | return status; | ||
241 | } | ||
242 | |||
243 | static int clk_vf_point_construct_volt(struct gk20a *g, | ||
244 | struct boardobj **ppboardobj, | ||
245 | u16 size, void *pargs) | ||
246 | { | ||
247 | struct boardobj *ptmpobj = (struct boardobj *)pargs; | ||
248 | struct clk_vf_point_volt *pclkvfpoint; | ||
249 | struct clk_vf_point_volt *ptmpvfpoint = | ||
250 | (struct clk_vf_point_volt *)pargs; | ||
251 | int status = 0; | ||
252 | |||
253 | if (BOARDOBJ_GET_TYPE(pargs) != CTRL_CLK_CLK_VF_POINT_TYPE_VOLT) { | ||
254 | return -EINVAL; | ||
255 | } | ||
256 | |||
257 | ptmpobj->type_mask = BIT(CTRL_CLK_CLK_VF_POINT_TYPE_VOLT); | ||
258 | status = clk_vf_point_construct_super(g, ppboardobj, size, pargs); | ||
259 | if (status) { | ||
260 | return -EINVAL; | ||
261 | } | ||
262 | |||
263 | pclkvfpoint = (struct clk_vf_point_volt *)*ppboardobj; | ||
264 | |||
265 | pclkvfpoint->super.super.pmudatainit = | ||
266 | _clk_vf_point_pmudatainit_volt; | ||
267 | |||
268 | pclkvfpoint->source_voltage_uv = ptmpvfpoint->source_voltage_uv; | ||
269 | pclkvfpoint->freq_delta = ptmpvfpoint->freq_delta; | ||
270 | |||
271 | return status; | ||
272 | } | ||
273 | |||
274 | static int clk_vf_point_construct_freq(struct gk20a *g, | ||
275 | struct boardobj **ppboardobj, | ||
276 | u16 size, void *pargs) | ||
277 | { | ||
278 | struct boardobj *ptmpobj = (struct boardobj *)pargs; | ||
279 | struct clk_vf_point_freq *pclkvfpoint; | ||
280 | struct clk_vf_point_freq *ptmpvfpoint = | ||
281 | (struct clk_vf_point_freq *)pargs; | ||
282 | int status = 0; | ||
283 | |||
284 | if (BOARDOBJ_GET_TYPE(pargs) != CTRL_CLK_CLK_VF_POINT_TYPE_FREQ) { | ||
285 | return -EINVAL; | ||
286 | } | ||
287 | |||
288 | ptmpobj->type_mask = BIT(CTRL_CLK_CLK_VF_POINT_TYPE_FREQ); | ||
289 | status = clk_vf_point_construct_super(g, ppboardobj, size, pargs); | ||
290 | if (status) { | ||
291 | return -EINVAL; | ||
292 | } | ||
293 | |||
294 | pclkvfpoint = (struct clk_vf_point_freq *)*ppboardobj; | ||
295 | |||
296 | pclkvfpoint->super.super.pmudatainit = | ||
297 | _clk_vf_point_pmudatainit_freq; | ||
298 | |||
299 | clkvfpointfreqmhzset(g, &pclkvfpoint->super, | ||
300 | clkvfpointfreqmhzget(g, &ptmpvfpoint->super)); | ||
301 | |||
302 | return status; | ||
303 | } | ||
304 | |||
305 | struct clk_vf_point *construct_clk_vf_point(struct gk20a *g, void *pargs) | ||
306 | { | ||
307 | struct boardobj *board_obj_ptr = NULL; | ||
308 | int status; | ||
309 | |||
310 | nvgpu_log_info(g, " "); | ||
311 | switch (BOARDOBJ_GET_TYPE(pargs)) { | ||
312 | case CTRL_CLK_CLK_VF_POINT_TYPE_FREQ: | ||
313 | status = clk_vf_point_construct_freq(g, &board_obj_ptr, | ||
314 | sizeof(struct clk_vf_point_freq), pargs); | ||
315 | break; | ||
316 | |||
317 | case CTRL_CLK_CLK_VF_POINT_TYPE_VOLT: | ||
318 | status = clk_vf_point_construct_volt(g, &board_obj_ptr, | ||
319 | sizeof(struct clk_vf_point_volt), pargs); | ||
320 | break; | ||
321 | |||
322 | default: | ||
323 | return NULL; | ||
324 | } | ||
325 | |||
326 | if (status) { | ||
327 | return NULL; | ||
328 | } | ||
329 | |||
330 | nvgpu_log_info(g, " Done"); | ||
331 | |||
332 | return (struct clk_vf_point *)board_obj_ptr; | ||
333 | } | ||
334 | |||
335 | static int _clk_vf_point_pmudatainit_super(struct gk20a *g, | ||
336 | struct boardobj *board_obj_ptr, | ||
337 | struct nv_pmu_boardobj *ppmudata) | ||
338 | { | ||
339 | int status = 0; | ||
340 | struct clk_vf_point *pclk_vf_point; | ||
341 | struct nv_pmu_clk_clk_vf_point_boardobj_set *pset; | ||
342 | |||
343 | nvgpu_log_info(g, " "); | ||
344 | |||
345 | status = boardobj_pmudatainit_super(g, board_obj_ptr, ppmudata); | ||
346 | if (status != 0) { | ||
347 | return status; | ||
348 | } | ||
349 | |||
350 | pclk_vf_point = | ||
351 | (struct clk_vf_point *)board_obj_ptr; | ||
352 | |||
353 | pset = (struct nv_pmu_clk_clk_vf_point_boardobj_set *) | ||
354 | ppmudata; | ||
355 | |||
356 | |||
357 | pset->vfe_equ_idx = pclk_vf_point->vfe_equ_idx; | ||
358 | pset->volt_rail_idx = pclk_vf_point->volt_rail_idx; | ||
359 | return status; | ||
360 | } | ||
361 | |||
362 | |||
363 | static int clk_vf_point_update(struct gk20a *g, | ||
364 | struct boardobj *board_obj_ptr, | ||
365 | struct nv_pmu_boardobj *ppmudata) | ||
366 | { | ||
367 | struct clk_vf_point *pclk_vf_point; | ||
368 | struct nv_pmu_clk_clk_vf_point_boardobj_get_status *pstatus; | ||
369 | |||
370 | nvgpu_log_info(g, " "); | ||
371 | |||
372 | |||
373 | pclk_vf_point = | ||
374 | (struct clk_vf_point *)board_obj_ptr; | ||
375 | |||
376 | pstatus = (struct nv_pmu_clk_clk_vf_point_boardobj_get_status *) | ||
377 | ppmudata; | ||
378 | |||
379 | if (pstatus->super.type != pclk_vf_point->super.type) { | ||
380 | nvgpu_err(g, | ||
381 | "pmu data and boardobj type not matching"); | ||
382 | return -EINVAL; | ||
383 | } | ||
384 | /* now copy VF pair */ | ||
385 | memcpy(&pclk_vf_point->pair, &pstatus->pair, | ||
386 | sizeof(struct ctrl_clk_vf_pair)); | ||
387 | return 0; | ||
388 | } | ||
389 | |||
390 | /*get latest vf point data from PMU */ | ||
391 | int clk_vf_point_cache(struct gk20a *g) | ||
392 | { | ||
393 | |||
394 | struct clk_vf_points *pclk_vf_points; | ||
395 | struct boardobjgrp *pboardobjgrp; | ||
396 | struct boardobjgrpmask *pboardobjgrpmask; | ||
397 | struct nv_pmu_boardobjgrp_super *pboardobjgrppmu; | ||
398 | struct boardobj *pboardobj = NULL; | ||
399 | struct nv_pmu_boardobj_query *pboardobjpmustatus = NULL; | ||
400 | int status; | ||
401 | u8 index; | ||
402 | |||
403 | nvgpu_log_info(g, " "); | ||
404 | pclk_vf_points = &g->clk_pmu.clk_vf_pointobjs; | ||
405 | pboardobjgrp = &pclk_vf_points->super.super; | ||
406 | pboardobjgrpmask = &pclk_vf_points->super.mask.super; | ||
407 | |||
408 | status = pboardobjgrp->pmugetstatus(g, pboardobjgrp, pboardobjgrpmask); | ||
409 | if (status) { | ||
410 | nvgpu_err(g, "err getting boardobjs from pmu"); | ||
411 | return status; | ||
412 | } | ||
413 | pboardobjgrppmu = pboardobjgrp->pmu.getstatus.buf; | ||
414 | |||
415 | BOARDOBJGRP_FOR_EACH(pboardobjgrp, struct boardobj*, pboardobj, index) { | ||
416 | status = pboardobjgrp->pmustatusinstget(g, | ||
417 | (struct nv_pmu_boardobjgrp *)pboardobjgrppmu, | ||
418 | &pboardobjpmustatus, index); | ||
419 | if (status) { | ||
420 | nvgpu_err(g, "could not get status object instance"); | ||
421 | return status; | ||
422 | } | ||
423 | |||
424 | status = clk_vf_point_update(g, pboardobj, | ||
425 | (struct nv_pmu_boardobj *)pboardobjpmustatus); | ||
426 | if (status) { | ||
427 | nvgpu_err(g, "invalid data from pmu at %d", index); | ||
428 | return status; | ||
429 | } | ||
430 | } | ||
431 | |||
432 | return 0; | ||
433 | } | ||