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