summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/clk/clk_vin.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/nvgpu/clk/clk_vin.c')
-rw-r--r--drivers/gpu/nvgpu/clk/clk_vin.c480
1 files changed, 480 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/clk/clk_vin.c b/drivers/gpu/nvgpu/clk/clk_vin.c
new file mode 100644
index 00000000..17e1c15a
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk_vin.c
@@ -0,0 +1,480 @@
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#include <nvgpu/bios.h>
24#include <nvgpu/pmuif/nvgpu_gpmu_cmdif.h>
25
26#include "gk20a/gk20a.h"
27
28#include "boardobj/boardobjgrp.h"
29#include "boardobj/boardobjgrp_e32.h"
30
31#include "ctrl/ctrlvolt.h"
32
33#include "gp106/bios_gp106.h"
34
35#include "clk.h"
36#include "clk_vin.h"
37
38#include <nvgpu/hw/gp106/hw_fuse_gp106.h>
39
40static u32 devinit_get_vin_device_table(struct gk20a *g,
41 struct avfsvinobjs *pvinobjs);
42
43static struct vin_device *construct_vin_device(struct gk20a *g, void *pargs);
44
45static u32 vin_device_init_pmudata_super(struct gk20a *g,
46 struct boardobj *board_obj_ptr,
47 struct nv_pmu_boardobj *ppmudata);
48
49static u32 read_vin_cal_fuse_rev(struct gk20a *g)
50{
51 return fuse_vin_cal_fuse_rev_data_v(
52 gk20a_readl(g, fuse_vin_cal_fuse_rev_r()));
53}
54
55static u32 read_vin_cal_slope_intercept_fuse(struct gk20a *g,
56 u32 vin_id, u32 *slope,
57 u32 *intercept)
58{
59 u32 data = 0;
60 u32 interceptdata = 0;
61 u32 slopedata = 0;
62 u32 gpc0data;
63 u32 gpc0slopedata;
64 u32 gpc0interceptdata;
65
66 /* read gpc0 irrespective of vin id */
67 gpc0data = gk20a_readl(g, fuse_vin_cal_gpc0_r());
68 if (gpc0data == 0xFFFFFFFF)
69 return -EINVAL;
70
71 switch (vin_id) {
72 case CTRL_CLK_VIN_ID_GPC0:
73 break;
74
75 case CTRL_CLK_VIN_ID_GPC1:
76 data = gk20a_readl(g, fuse_vin_cal_gpc1_delta_r());
77 break;
78
79 case CTRL_CLK_VIN_ID_GPC2:
80 data = gk20a_readl(g, fuse_vin_cal_gpc2_delta_r());
81 break;
82
83 case CTRL_CLK_VIN_ID_GPC3:
84 data = gk20a_readl(g, fuse_vin_cal_gpc3_delta_r());
85 break;
86
87 case CTRL_CLK_VIN_ID_GPC4:
88 data = gk20a_readl(g, fuse_vin_cal_gpc4_delta_r());
89 break;
90
91 case CTRL_CLK_VIN_ID_GPC5:
92 data = gk20a_readl(g, fuse_vin_cal_gpc5_delta_r());
93 break;
94
95 case CTRL_CLK_VIN_ID_SYS:
96 case CTRL_CLK_VIN_ID_XBAR:
97 case CTRL_CLK_VIN_ID_LTC:
98 data = gk20a_readl(g, fuse_vin_cal_shared_delta_r());
99 break;
100
101 case CTRL_CLK_VIN_ID_SRAM:
102 data = gk20a_readl(g, fuse_vin_cal_sram_delta_r());
103 break;
104
105 default:
106 return -EINVAL;
107 }
108 if (data == 0xFFFFFFFF)
109 return -EINVAL;
110
111 gpc0interceptdata = (fuse_vin_cal_gpc0_icpt_int_data_v(gpc0data) <<
112 fuse_vin_cal_gpc0_icpt_frac_data_s()) +
113 fuse_vin_cal_gpc0_icpt_frac_data_v(gpc0data);
114 gpc0interceptdata = (gpc0interceptdata * 1000U) >>
115 fuse_vin_cal_gpc0_icpt_frac_data_s();
116
117 switch (vin_id) {
118 case CTRL_CLK_VIN_ID_GPC0:
119 break;
120
121 case CTRL_CLK_VIN_ID_GPC1:
122 case CTRL_CLK_VIN_ID_GPC2:
123 case CTRL_CLK_VIN_ID_GPC3:
124 case CTRL_CLK_VIN_ID_GPC4:
125 case CTRL_CLK_VIN_ID_GPC5:
126 case CTRL_CLK_VIN_ID_SYS:
127 case CTRL_CLK_VIN_ID_XBAR:
128 case CTRL_CLK_VIN_ID_LTC:
129 interceptdata = (fuse_vin_cal_gpc1_delta_icpt_int_data_v(data) <<
130 fuse_vin_cal_gpc1_delta_icpt_frac_data_s()) +
131 fuse_vin_cal_gpc1_delta_icpt_frac_data_v(data);
132 interceptdata = (interceptdata * 1000U) >>
133 fuse_vin_cal_gpc1_delta_icpt_frac_data_s();
134 break;
135
136 case CTRL_CLK_VIN_ID_SRAM:
137 interceptdata = (fuse_vin_cal_sram_delta_icpt_int_data_v(data) <<
138 fuse_vin_cal_sram_delta_icpt_frac_data_s()) +
139 fuse_vin_cal_sram_delta_icpt_frac_data_v(data);
140 interceptdata = (interceptdata * 1000U) >>
141 fuse_vin_cal_sram_delta_icpt_frac_data_s();
142 break;
143
144 default:
145 return -EINVAL;
146 }
147
148 if (fuse_vin_cal_gpc1_delta_icpt_sign_data_v(data))
149 *intercept = gpc0interceptdata - interceptdata;
150 else
151 *intercept = gpc0interceptdata + interceptdata;
152
153 /* slope */
154 gpc0slopedata = (fuse_vin_cal_gpc0_slope_int_data_v(gpc0data) <<
155 fuse_vin_cal_gpc0_slope_frac_data_s()) +
156 fuse_vin_cal_gpc0_slope_frac_data_v(gpc0data);
157 gpc0slopedata = (gpc0slopedata * 1000U) >>
158 fuse_vin_cal_gpc0_slope_frac_data_s();
159 switch (vin_id) {
160 case CTRL_CLK_VIN_ID_GPC0:
161 break;
162
163 case CTRL_CLK_VIN_ID_GPC1:
164 case CTRL_CLK_VIN_ID_GPC2:
165 case CTRL_CLK_VIN_ID_GPC3:
166 case CTRL_CLK_VIN_ID_GPC4:
167 case CTRL_CLK_VIN_ID_GPC5:
168 case CTRL_CLK_VIN_ID_SYS:
169 case CTRL_CLK_VIN_ID_XBAR:
170 case CTRL_CLK_VIN_ID_LTC:
171 case CTRL_CLK_VIN_ID_SRAM:
172 slopedata =
173 (fuse_vin_cal_gpc1_delta_slope_int_data_v(data)) * 1000;
174 break;
175
176 default:
177 return -EINVAL;
178 }
179
180 if (fuse_vin_cal_gpc1_delta_slope_sign_data_v(data))
181 *slope = gpc0slopedata - slopedata;
182 else
183 *slope = gpc0slopedata + slopedata;
184 return 0;
185}
186
187static u32 _clk_vin_devgrp_pmudatainit_super(struct gk20a *g,
188 struct boardobjgrp *pboardobjgrp,
189 struct nv_pmu_boardobjgrp_super *pboardobjgrppmu)
190{
191 struct nv_pmu_clk_clk_vin_device_boardobjgrp_set_header *pset =
192 (struct nv_pmu_clk_clk_vin_device_boardobjgrp_set_header *)
193 pboardobjgrppmu;
194 struct avfsvinobjs *pvin_obbj = (struct avfsvinobjs *)pboardobjgrp;
195 u32 status = 0;
196
197 gk20a_dbg_info("");
198
199 status = boardobjgrp_pmudatainit_e32(g, pboardobjgrp, pboardobjgrppmu);
200
201 pset->b_vin_is_disable_allowed = pvin_obbj->vin_is_disable_allowed;
202
203 gk20a_dbg_info(" Done");
204 return status;
205}
206
207static u32 _clk_vin_devgrp_pmudata_instget(struct gk20a *g,
208 struct nv_pmu_boardobjgrp *pmuboardobjgrp,
209 struct nv_pmu_boardobj **ppboardobjpmudata,
210 u8 idx)
211{
212 struct nv_pmu_clk_clk_vin_device_boardobj_grp_set *pgrp_set =
213 (struct nv_pmu_clk_clk_vin_device_boardobj_grp_set *)
214 pmuboardobjgrp;
215
216 gk20a_dbg_info("");
217
218 /*check whether pmuboardobjgrp has a valid boardobj in index*/
219 if (((u32)BIT(idx) &
220 pgrp_set->hdr.data.super.obj_mask.super.data[0]) == 0)
221 return -EINVAL;
222
223 *ppboardobjpmudata = (struct nv_pmu_boardobj *)
224 &pgrp_set->objects[idx].data.board_obj;
225 gk20a_dbg_info(" Done");
226 return 0;
227}
228
229static u32 _clk_vin_devgrp_pmustatus_instget(struct gk20a *g,
230 void *pboardobjgrppmu,
231 struct nv_pmu_boardobj_query **ppboardobjpmustatus,
232 u8 idx)
233{
234 struct nv_pmu_clk_clk_vin_device_boardobj_grp_get_status *pgrp_get_status =
235 (struct nv_pmu_clk_clk_vin_device_boardobj_grp_get_status *)
236 pboardobjgrppmu;
237
238 /*check whether pmuboardobjgrp has a valid boardobj in index*/
239 if (((u32)BIT(idx) &
240 pgrp_get_status->hdr.data.super.obj_mask.super.data[0]) == 0)
241 return -EINVAL;
242
243 *ppboardobjpmustatus = (struct nv_pmu_boardobj_query *)
244 &pgrp_get_status->objects[idx].data.board_obj;
245 return 0;
246}
247
248u32 clk_vin_sw_setup(struct gk20a *g)
249{
250 u32 status;
251 struct boardobjgrp *pboardobjgrp = NULL;
252 u32 slope;
253 u32 intercept;
254 struct vin_device *pvindev;
255 struct avfsvinobjs *pvinobjs;
256 u8 i;
257
258 gk20a_dbg_info("");
259
260 status = boardobjgrpconstruct_e32(g, &g->clk_pmu.avfs_vinobjs.super);
261 if (status) {
262 nvgpu_err(g,
263 "error creating boardobjgrp for clk vin, statu - 0x%x",
264 status);
265 goto done;
266 }
267
268 pboardobjgrp = &g->clk_pmu.avfs_vinobjs.super.super;
269 pvinobjs = &g->clk_pmu.avfs_vinobjs;
270
271 BOARDOBJGRP_PMU_CONSTRUCT(pboardobjgrp, CLK, VIN_DEVICE);
272
273 status = BOARDOBJGRP_PMU_CMD_GRP_SET_CONSTRUCT(g, pboardobjgrp,
274 clk, CLK, clk_vin_device, CLK_VIN_DEVICE);
275 if (status) {
276 nvgpu_err(g,
277 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
278 status);
279 goto done;
280 }
281
282 pboardobjgrp->pmudatainit = _clk_vin_devgrp_pmudatainit_super;
283 pboardobjgrp->pmudatainstget = _clk_vin_devgrp_pmudata_instget;
284 pboardobjgrp->pmustatusinstget = _clk_vin_devgrp_pmustatus_instget;
285
286 status = devinit_get_vin_device_table(g, &g->clk_pmu.avfs_vinobjs);
287 if (status)
288 goto done;
289
290 /*update vin calibration to fuse */
291 if (pvinobjs->calibration_rev_vbios == read_vin_cal_fuse_rev(g)) {
292 BOARDOBJGRP_FOR_EACH(&(pvinobjs->super.super),
293 struct vin_device *, pvindev, i) {
294 slope = 0;
295 intercept = 0;
296 pvindev = CLK_GET_VIN_DEVICE(pvinobjs, i);
297 status = read_vin_cal_slope_intercept_fuse(g,
298 pvindev->id, &slope, &intercept);
299 if (status) {
300 nvgpu_err(g,
301 "err reading vin cal for id %x", pvindev->id);
302 goto done;
303 }
304 if (slope != 0 && intercept != 0) {
305 pvindev->slope = slope;
306 pvindev->intercept = intercept;
307 }
308 }
309 }
310 status = BOARDOBJGRP_PMU_CMD_GRP_GET_STATUS_CONSTRUCT(g,
311 &g->clk_pmu.avfs_vinobjs.super.super,
312 clk, CLK, clk_vin_device, CLK_VIN_DEVICE);
313 if (status) {
314 nvgpu_err(g,
315 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
316 status);
317 goto done;
318 }
319
320done:
321 gk20a_dbg_info(" done status %x", status);
322 return status;
323}
324
325u32 clk_vin_pmu_setup(struct gk20a *g)
326{
327 u32 status;
328 struct boardobjgrp *pboardobjgrp = NULL;
329
330 gk20a_dbg_info("");
331
332 pboardobjgrp = &g->clk_pmu.avfs_vinobjs.super.super;
333
334 if (!pboardobjgrp->bconstructed)
335 return -EINVAL;
336
337 status = pboardobjgrp->pmuinithandle(g, pboardobjgrp);
338
339 gk20a_dbg_info("Done");
340 return status;
341}
342
343static u32 devinit_get_vin_device_table(struct gk20a *g,
344 struct avfsvinobjs *pvinobjs)
345{
346 u32 status = 0;
347 u8 *vin_table_ptr = NULL;
348 struct vin_descriptor_header_10 vin_desc_table_header = { 0 };
349 struct vin_descriptor_entry_10 vin_desc_table_entry = { 0 };
350 u8 *vin_tbl_entry_ptr = NULL;
351 u32 index = 0;
352 u32 slope, intercept;
353 struct vin_device vin_dev_data;
354 struct vin_device *pvin_dev;
355
356 gk20a_dbg_info("");
357
358 vin_table_ptr = (u8 *)nvgpu_bios_get_perf_table_ptrs(g,
359 g->bios.clock_token, VIN_TABLE);
360 if (vin_table_ptr == NULL) {
361 status = -1;
362 goto done;
363 }
364
365 memcpy(&vin_desc_table_header, vin_table_ptr,
366 sizeof(struct vin_descriptor_header_10));
367
368 pvinobjs->calibration_rev_vbios =
369 BIOS_GET_FIELD(vin_desc_table_header.flags0,
370 NV_VIN_DESC_FLAGS0_VIN_CAL_REVISION);
371 pvinobjs->vin_is_disable_allowed =
372 BIOS_GET_FIELD(vin_desc_table_header.flags0,
373 NV_VIN_DESC_FLAGS0_DISABLE_CONTROL);
374
375 /* VIN calibration slope: XX.YYY mV/code => XXYYY uV/code*/
376 slope = ((BIOS_GET_FIELD(vin_desc_table_header.vin_cal,
377 NV_VIN_DESC_VIN_CAL_SLOPE_INTEGER) * 1000)) +
378 ((BIOS_GET_FIELD(vin_desc_table_header.vin_cal,
379 NV_VIN_DESC_VIN_CAL_SLOPE_FRACTION)));
380
381 /* VIN calibration intercept: ZZZ.W mV => ZZZW00 uV */
382 intercept = ((BIOS_GET_FIELD(vin_desc_table_header.vin_cal,
383 NV_VIN_DESC_VIN_CAL_INTERCEPT_INTEGER) * 1000)) +
384 ((BIOS_GET_FIELD(vin_desc_table_header.vin_cal,
385 NV_VIN_DESC_VIN_CAL_INTERCEPT_FRACTION) * 100));
386
387 /* Read table entries*/
388 vin_tbl_entry_ptr = vin_table_ptr + vin_desc_table_header.header_sizee;
389 for (index = 0; index < vin_desc_table_header.entry_count; index++) {
390 u32 vin_id;
391
392 memcpy(&vin_desc_table_entry, vin_tbl_entry_ptr,
393 sizeof(struct vin_descriptor_entry_10));
394
395 if (vin_desc_table_entry.vin_device_type == CTRL_CLK_VIN_TYPE_DISABLED)
396 continue;
397
398 vin_id = vin_desc_table_entry.vin_device_id;
399
400 vin_dev_data.super.type =
401 (u8)vin_desc_table_entry.vin_device_type;
402 vin_dev_data.id = (u8)vin_desc_table_entry.vin_device_id;
403 vin_dev_data.volt_domain_vbios =
404 (u8)vin_desc_table_entry.volt_domain_vbios;
405 vin_dev_data.slope = slope;
406 vin_dev_data.intercept = intercept;
407
408 vin_dev_data.flls_shared_mask = 0;
409
410 pvin_dev = construct_vin_device(g, (void *)&vin_dev_data);
411
412 status = boardobjgrp_objinsert(&pvinobjs->super.super,
413 (struct boardobj *)pvin_dev, index);
414
415 vin_tbl_entry_ptr += vin_desc_table_header.entry_size;
416 }
417
418done:
419 gk20a_dbg_info(" done status %x", status);
420 return status;
421}
422
423static struct vin_device *construct_vin_device(struct gk20a *g, void *pargs)
424{
425 struct boardobj *board_obj_ptr = NULL;
426 struct vin_device *pvin_dev;
427 struct vin_device *board_obj_vin_ptr = NULL;
428 u32 status;
429
430 gk20a_dbg_info("");
431 status = boardobj_construct_super(g, &board_obj_ptr,
432 sizeof(struct vin_device), pargs);
433 if (status)
434 return NULL;
435
436 /*got vin board obj allocated now fill it into boardobj grp*/
437 pvin_dev = (struct vin_device *)pargs;
438 board_obj_vin_ptr = (struct vin_device *)board_obj_ptr;
439 /* override super class interface */
440 board_obj_ptr->pmudatainit = vin_device_init_pmudata_super;
441 board_obj_vin_ptr->id = pvin_dev->id;
442 board_obj_vin_ptr->volt_domain_vbios = pvin_dev->volt_domain_vbios;
443 board_obj_vin_ptr->slope = pvin_dev->slope;
444 board_obj_vin_ptr->intercept = pvin_dev->intercept;
445 board_obj_vin_ptr->flls_shared_mask = pvin_dev->flls_shared_mask;
446 board_obj_vin_ptr->volt_domain = CTRL_VOLT_DOMAIN_LOGIC;
447
448 gk20a_dbg_info(" Done");
449
450 return (struct vin_device *)board_obj_ptr;
451}
452
453static u32 vin_device_init_pmudata_super(struct gk20a *g,
454 struct boardobj *board_obj_ptr,
455 struct nv_pmu_boardobj *ppmudata)
456{
457 u32 status = 0;
458 struct vin_device *pvin_dev;
459 struct nv_pmu_clk_clk_vin_device_boardobj_set *perf_pmu_data;
460
461 gk20a_dbg_info("");
462
463 status = boardobj_pmudatainit_super(g, board_obj_ptr, ppmudata);
464 if (status != 0)
465 return status;
466
467 pvin_dev = (struct vin_device *)board_obj_ptr;
468 perf_pmu_data = (struct nv_pmu_clk_clk_vin_device_boardobj_set *)
469 ppmudata;
470
471 perf_pmu_data->id = pvin_dev->id;
472 perf_pmu_data->intercept = pvin_dev->intercept;
473 perf_pmu_data->volt_domain = pvin_dev->volt_domain;
474 perf_pmu_data->slope = pvin_dev->slope;
475 perf_pmu_data->flls_shared_mask = pvin_dev->flls_shared_mask;
476
477 gk20a_dbg_info(" Done");
478
479 return status;
480}