summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/clk/clk_vin.c
diff options
context:
space:
mode:
authorVijayakumar Subbu <vsubbu@nvidia.com>2016-07-30 13:44:30 -0400
committerDeepak Nibade <dnibade@nvidia.com>2016-12-27 04:56:49 -0500
commit432017248e432df0619dc2df30f915a52634338f (patch)
tree40bb7a77983fb2753271bc46b346a44ebd6121cf /drivers/gpu/nvgpu/clk/clk_vin.c
parent38ad90b4840434df4650c617a236e1b01f8a43c6 (diff)
gpu: nvgpu: Add dGPU clocks support
JIRA DNVGPU-42 Change-Id: Ic2fca9d0cf82f2823654ac5e8f0772a1eec7b3b5 Signed-off-by: Vijayakumar Subbu <vsubbu@nvidia.com> Signed-off-by: Terje Bergstrom <tbergstrom@nvidia.com> Reviewed-on: http://git-master/r/1205850 (cherry picked from commit b9f5c6bc4e649162d63e33d65b725872340ca114) Reviewed-on: http://git-master/r/1227257 GVS: Gerrit_Virtual_Submit
Diffstat (limited to 'drivers/gpu/nvgpu/clk/clk_vin.c')
-rw-r--r--drivers/gpu/nvgpu/clk/clk_vin.c466
1 files changed, 466 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..e8e4b753
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk_vin.c
@@ -0,0 +1,466 @@
1/*
2 * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 */
13
14#include "gk20a/gk20a.h"
15#include "clk.h"
16#include "clk_vin.h"
17#include "include/bios.h"
18#include "boardobj/boardobjgrp.h"
19#include "boardobj/boardobjgrp_e32.h"
20#include "pmuif/gpmuifboardobj.h"
21#include "pmuif/gpmuifclk.h"
22#include "gm206/bios_gm206.h"
23#include "ctrl/ctrlvolt.h"
24#include "gk20a/pmu_gk20a.h"
25#include "gp106/hw_fuse_gp106.h"
26
27static u32 devinit_get_vin_device_table(struct gk20a *g,
28 struct avfsvinobjs *pvinobjs);
29
30static struct vin_device *construct_vin_device(struct gk20a *g, void *pargs);
31
32static u32 vin_device_init_pmudata_super(struct gk20a *g,
33 struct boardobj *board_obj_ptr,
34 struct nv_pmu_boardobj *ppmudata);
35
36static u32 read_vin_cal_fuse_rev(struct gk20a *g)
37{
38 return fuse_vin_cal_fuse_rev_v(
39 gk20a_readl(g, fuse_vin_cal_fuse_rev_r()));
40}
41
42static u32 read_vin_cal_slope_intercept_fuse(struct gk20a *g,
43 u32 vin_id, u32 *slope,
44 u32 *intercept)
45{
46 u32 data = 0;
47 u32 interceptdata = 0;
48 u32 slopedata = 0;
49 u32 gpc0data;
50 u32 gpc0slopedata;
51 u32 gpc0interceptdata;
52
53 /* read gpc0 irrespective of vin id */
54 gpc0data = gk20a_readl(g, fuse_vin_cal_gpc0_r());
55 if (gpc0data == 0xFFFFFFFF)
56 return -EINVAL;
57
58 switch (vin_id) {
59 case CTRL_CLK_VIN_ID_GPC0:
60 break;
61
62 case CTRL_CLK_VIN_ID_GPC1:
63 data = gk20a_readl(g, fuse_vin_cal_gpc1_delta_r());
64 break;
65
66 case CTRL_CLK_VIN_ID_GPC2:
67 data = gk20a_readl(g, fuse_vin_cal_gpc2_delta_r());
68 break;
69
70 case CTRL_CLK_VIN_ID_GPC3:
71 data = gk20a_readl(g, fuse_vin_cal_gpc3_delta_r());
72 break;
73
74 case CTRL_CLK_VIN_ID_GPC4:
75 data = gk20a_readl(g, fuse_vin_cal_gpc4_delta_r());
76 break;
77
78 case CTRL_CLK_VIN_ID_GPC5:
79 data = gk20a_readl(g, fuse_vin_cal_gpc5_delta_r());
80 break;
81
82 case CTRL_CLK_VIN_ID_SYS:
83 case CTRL_CLK_VIN_ID_XBAR:
84 case CTRL_CLK_VIN_ID_LTC:
85 data = gk20a_readl(g, fuse_vin_cal_shared_delta_r());
86 break;
87
88 case CTRL_CLK_VIN_ID_SRAM:
89 data = gk20a_readl(g, fuse_vin_cal_sram_delta_r());
90 break;
91
92 default:
93 return -EINVAL;
94 }
95 if (data == 0xFFFFFFFF)
96 return -EINVAL;
97
98 gpc0interceptdata = fuse_vin_cal_gpc0_icpt_data_v(gpc0data) * 1000;
99 gpc0interceptdata = gpc0interceptdata >>
100 fuse_vin_cal_gpc0_icpt_frac_size_v();
101
102 switch (vin_id) {
103 case CTRL_CLK_VIN_ID_GPC0:
104 break;
105
106 case CTRL_CLK_VIN_ID_GPC1:
107 case CTRL_CLK_VIN_ID_GPC2:
108 case CTRL_CLK_VIN_ID_GPC3:
109 case CTRL_CLK_VIN_ID_GPC4:
110 case CTRL_CLK_VIN_ID_GPC5:
111 case CTRL_CLK_VIN_ID_SYS:
112 case CTRL_CLK_VIN_ID_XBAR:
113 case CTRL_CLK_VIN_ID_LTC:
114 interceptdata =
115 (fuse_vin_cal_gpc1_icpt_data_v(data)) * 1000;
116 interceptdata = interceptdata >>
117 fuse_vin_cal_gpc1_icpt_frac_size_v();
118 break;
119
120 case CTRL_CLK_VIN_ID_SRAM:
121 interceptdata =
122 (fuse_vin_cal_sram_icpt_data_v(data)) * 1000;
123 interceptdata = interceptdata >>
124 fuse_vin_cal_sram_icpt_frac_size_v();
125 break;
126
127 default:
128 return -EINVAL;
129 }
130
131 if (data & fuse_vin_cal_gpc1_icpt_sign_f())
132 *intercept = gpc0interceptdata - interceptdata;
133 else
134 *intercept = gpc0interceptdata + interceptdata;
135
136 /* slope */
137 gpc0slopedata = (fuse_vin_cal_gpc0_slope_data_v(gpc0data)) * 1000;
138 gpc0slopedata = gpc0slopedata >>
139 fuse_vin_cal_gpc0_slope_frac_size_v();
140
141 switch (vin_id) {
142 case CTRL_CLK_VIN_ID_GPC0:
143 break;
144
145 case CTRL_CLK_VIN_ID_GPC1:
146 case CTRL_CLK_VIN_ID_GPC2:
147 case CTRL_CLK_VIN_ID_GPC3:
148 case CTRL_CLK_VIN_ID_GPC4:
149 case CTRL_CLK_VIN_ID_GPC5:
150 case CTRL_CLK_VIN_ID_SYS:
151 case CTRL_CLK_VIN_ID_XBAR:
152 case CTRL_CLK_VIN_ID_LTC:
153 case CTRL_CLK_VIN_ID_SRAM:
154 slopedata =
155 (fuse_vin_cal_gpc1_slope_data_v(data)) * 1000;
156 slopedata = slopedata >>
157 fuse_vin_cal_gpc1_slope_frac_size_v();
158 break;
159
160 default:
161 return -EINVAL;
162 }
163
164 if (data & fuse_vin_cal_gpc1_slope_sign_f())
165 *slope = gpc0slopedata - slopedata;
166 else
167 *slope = gpc0slopedata + slopedata;
168 return 0;
169}
170
171static u32 _clk_vin_devgrp_pmudatainit_super(struct gk20a *g,
172 struct boardobjgrp *pboardobjgrp,
173 struct nv_pmu_boardobjgrp_super *pboardobjgrppmu)
174{
175 struct nv_pmu_clk_clk_vin_device_boardobjgrp_set_header *pset =
176 (struct nv_pmu_clk_clk_vin_device_boardobjgrp_set_header *)
177 pboardobjgrppmu;
178 struct avfsvinobjs *pvin_obbj = (struct avfsvinobjs *)pboardobjgrp;
179 u32 status = 0;
180
181 gk20a_dbg_info("");
182
183 status = boardobjgrp_pmudatainit_e32(g, pboardobjgrp, pboardobjgrppmu);
184
185 pset->b_vin_is_disable_allowed = pvin_obbj->vin_is_disable_allowed;
186
187 gk20a_dbg_info(" Done");
188 return status;
189}
190
191static u32 _clk_vin_devgrp_pmudata_instget(struct gk20a *g,
192 struct nv_pmu_boardobjgrp *pmuboardobjgrp,
193 struct nv_pmu_boardobj **ppboardobjpmudata,
194 u8 idx)
195{
196 struct nv_pmu_clk_clk_vin_device_boardobj_grp_set *pgrp_set =
197 (struct nv_pmu_clk_clk_vin_device_boardobj_grp_set *)
198 pmuboardobjgrp;
199
200 gk20a_dbg_info("");
201
202 /*check whether pmuboardobjgrp has a valid boardobj in index*/
203 if (((u32)BIT(idx) &
204 pgrp_set->hdr.data.super.obj_mask.super.data[0]) == 0)
205 return -EINVAL;
206
207 *ppboardobjpmudata = (struct nv_pmu_boardobj *)
208 &pgrp_set->objects[idx].data.board_obj;
209 gk20a_dbg_info(" Done");
210 return 0;
211}
212
213static u32 _clk_vin_devgrp_pmustatus_instget(struct gk20a *g,
214 void *pboardobjgrppmu,
215 struct nv_pmu_boardobj_query **ppboardobjpmustatus,
216 u8 idx)
217{
218 struct nv_pmu_clk_clk_vin_device_boardobj_grp_get_status *pgrp_get_status =
219 (struct nv_pmu_clk_clk_vin_device_boardobj_grp_get_status *)
220 pboardobjgrppmu;
221
222 /*check whether pmuboardobjgrp has a valid boardobj in index*/
223 if (((u32)BIT(idx) &
224 pgrp_get_status->hdr.data.super.obj_mask.super.data[0]) == 0)
225 return -EINVAL;
226
227 *ppboardobjpmustatus = (struct nv_pmu_boardobj_query *)
228 &pgrp_get_status->objects[idx].data.board_obj;
229 return 0;
230}
231
232u32 clk_vin_sw_setup(struct gk20a *g)
233{
234 u32 status;
235 struct boardobjgrp *pboardobjgrp = NULL;
236 u32 slope;
237 u32 intercept;
238 struct vin_device *pvindev;
239 struct avfsvinobjs *pvinobjs;
240 u8 i;
241
242 gk20a_dbg_info("");
243
244 status = boardobjgrpconstruct_e32(&g->clk_pmu.avfs_vinobjs.super);
245 if (status) {
246 gk20a_err(dev_from_gk20a(g),
247 "error creating boardobjgrp for clk vin, statu - 0x%x",
248 status);
249 goto done;
250 }
251
252 pboardobjgrp = &g->clk_pmu.avfs_vinobjs.super.super;
253 pvinobjs = &g->clk_pmu.avfs_vinobjs;
254
255 BOARDOBJGRP_PMU_CONSTRUCT(pboardobjgrp, CLK, VIN_DEVICE);
256
257 status = BOARDOBJGRP_PMU_CMD_GRP_SET_CONSTRUCT(g, pboardobjgrp,
258 clk, CLK, clk_vin_device, CLK_VIN_DEVICE);
259 if (status) {
260 gk20a_err(dev_from_gk20a(g),
261 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
262 status);
263 goto done;
264 }
265
266 pboardobjgrp->pmudatainit = _clk_vin_devgrp_pmudatainit_super;
267 pboardobjgrp->pmudatainstget = _clk_vin_devgrp_pmudata_instget;
268 pboardobjgrp->pmustatusinstget = _clk_vin_devgrp_pmustatus_instget;
269
270 status = devinit_get_vin_device_table(g, &g->clk_pmu.avfs_vinobjs);
271 if (status)
272 goto done;
273
274 /*update vin calibration to fuse */
275 if (pvinobjs->calibration_rev_vbios == read_vin_cal_fuse_rev(g)) {
276 BOARDOBJGRP_FOR_EACH(&(pvinobjs->super.super),
277 struct vin_device *, pvindev, i) {
278 slope = 0;
279 intercept = 0;
280 pvindev = CLK_GET_VIN_DEVICE(pvinobjs, i);
281 status = read_vin_cal_slope_intercept_fuse(g,
282 pvindev->id, &slope, &intercept);
283 if (status) {
284 gk20a_err(dev_from_gk20a(g),
285 "err reading vin cal for id %x", pvindev->id);
286 goto done;
287 }
288 if (slope != 0 && intercept != 0) {
289 pvindev->slope = slope;
290 pvindev->intercept = intercept;
291 }
292 }
293 }
294 status = BOARDOBJGRP_PMU_CMD_GRP_GET_STATUS_CONSTRUCT(g,
295 &g->clk_pmu.avfs_vinobjs.super.super,
296 clk, CLK, clk_vin_device, CLK_VIN_DEVICE);
297 if (status) {
298 gk20a_err(dev_from_gk20a(g),
299 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
300 status);
301 goto done;
302 }
303
304done:
305 gk20a_dbg_info(" done status %x", status);
306 return status;
307}
308
309u32 clk_vin_pmu_setup(struct gk20a *g)
310{
311 u32 status;
312 struct boardobjgrp *pboardobjgrp = NULL;
313
314 gk20a_dbg_info("");
315
316 pboardobjgrp = &g->clk_pmu.avfs_vinobjs.super.super;
317
318 if (!pboardobjgrp->bconstructed)
319 return -EINVAL;
320
321 status = pboardobjgrp->pmuinithandle(g, pboardobjgrp);
322
323 gk20a_dbg_info("Done");
324 return status;
325}
326
327static u32 devinit_get_vin_device_table(struct gk20a *g,
328 struct avfsvinobjs *pvinobjs)
329{
330 u32 status = 0;
331 u8 *vin_table_ptr = NULL;
332 struct vin_descriptor_header_10 vin_desc_table_header = { 0 };
333 struct vin_descriptor_entry_10 vin_desc_table_entry = { 0 };
334 u8 *vin_tbl_entry_ptr = NULL;
335 u32 index = 0;
336 u32 slope, intercept;
337 struct vin_device vin_dev_data;
338 struct vin_device *pvin_dev;
339
340 gk20a_dbg_info("");
341
342 if (g->ops.bios.get_perf_table_ptrs) {
343 vin_table_ptr = (u8 *)g->ops.bios.get_perf_table_ptrs(g,
344 g->bios.clock_token, VIN_TABLE);
345 if (vin_table_ptr == NULL) {
346 status = -1;
347 goto done;
348 }
349 }
350
351 memcpy(&vin_desc_table_header, vin_table_ptr,
352 sizeof(struct vin_descriptor_header_10));
353
354 pvinobjs->calibration_rev_vbios =
355 BIOS_GET_FIELD(vin_desc_table_header.flags0,
356 NV_VIN_DESC_FLAGS0_VIN_CAL_REVISION);
357 pvinobjs->vin_is_disable_allowed =
358 BIOS_GET_FIELD(vin_desc_table_header.flags0,
359 NV_VIN_DESC_FLAGS0_DISABLE_CONTROL);
360
361 /* VIN calibration slope: XX.YYY mV/code => XXYYY uV/code*/
362 slope = ((BIOS_GET_FIELD(vin_desc_table_header.vin_cal,
363 NV_VIN_DESC_VIN_CAL_SLOPE_INTEGER) * 1000)) +
364 ((BIOS_GET_FIELD(vin_desc_table_header.vin_cal,
365 NV_VIN_DESC_VIN_CAL_SLOPE_FRACTION)));
366
367 /* VIN calibration intercept: ZZZ.W mV => ZZZW00 uV */
368 intercept = ((BIOS_GET_FIELD(vin_desc_table_header.vin_cal,
369 NV_VIN_DESC_VIN_CAL_INTERCEPT_INTEGER) * 1000)) +
370 ((BIOS_GET_FIELD(vin_desc_table_header.vin_cal,
371 NV_VIN_DESC_VIN_CAL_INTERCEPT_FRACTION) * 100));
372
373 /* Read table entries*/
374 vin_tbl_entry_ptr = vin_table_ptr + vin_desc_table_header.header_sizee;
375 for (index = 0; index < vin_desc_table_header.entry_count; index++) {
376 u32 vin_id;
377
378 memcpy(&vin_desc_table_entry, vin_tbl_entry_ptr,
379 sizeof(struct vin_descriptor_entry_10));
380
381 if (vin_desc_table_entry.vin_device_type == CTRL_CLK_VIN_TYPE_DISABLED)
382 continue;
383
384 vin_id = vin_desc_table_entry.vin_device_id;
385
386 vin_dev_data.super.type =
387 (u8)vin_desc_table_entry.vin_device_type;
388 vin_dev_data.id = (u8)vin_desc_table_entry.vin_device_id;
389 vin_dev_data.volt_domain_vbios =
390 (u8)vin_desc_table_entry.volt_domain_vbios;
391 vin_dev_data.slope = slope;
392 vin_dev_data.intercept = intercept;
393
394 vin_dev_data.flls_shared_mask = 0;
395
396 pvin_dev = construct_vin_device(g, (void *)&vin_dev_data);
397
398 status = boardobjgrp_objinsert(&pvinobjs->super.super,
399 (struct boardobj *)pvin_dev, index);
400
401 vin_tbl_entry_ptr += vin_desc_table_header.entry_size;
402 }
403
404done:
405 gk20a_dbg_info(" done status %x", status);
406 return status;
407}
408
409static struct vin_device *construct_vin_device(struct gk20a *g, void *pargs)
410{
411 struct boardobj *board_obj_ptr = NULL;
412 struct vin_device *pvin_dev;
413 struct vin_device *board_obj_vin_ptr = NULL;
414 u32 status;
415
416 gk20a_dbg_info("");
417 status = boardobj_construct_super(g, &board_obj_ptr,
418 sizeof(struct vin_device), pargs);
419 if (status)
420 return NULL;
421
422 /*got vin board obj allocated now fill it into boardobj grp*/
423 pvin_dev = (struct vin_device *)pargs;
424 board_obj_vin_ptr = (struct vin_device *)board_obj_ptr;
425 /* override super class interface */
426 board_obj_ptr->pmudatainit = vin_device_init_pmudata_super;
427 board_obj_vin_ptr->id = pvin_dev->id;
428 board_obj_vin_ptr->volt_domain_vbios = pvin_dev->volt_domain_vbios;
429 board_obj_vin_ptr->slope = pvin_dev->slope;
430 board_obj_vin_ptr->intercept = pvin_dev->intercept;
431 board_obj_vin_ptr->flls_shared_mask = pvin_dev->flls_shared_mask;
432 board_obj_vin_ptr->volt_domain = CTRL_VOLT_DOMAIN_LOGIC;
433
434 gk20a_dbg_info(" Done");
435
436 return (struct vin_device *)board_obj_ptr;
437}
438
439static u32 vin_device_init_pmudata_super(struct gk20a *g,
440 struct boardobj *board_obj_ptr,
441 struct nv_pmu_boardobj *ppmudata)
442{
443 u32 status = 0;
444 struct vin_device *pvin_dev;
445 struct nv_pmu_clk_clk_vin_device_boardobj_set *perf_pmu_data;
446
447 gk20a_dbg_info("");
448
449 status = boardobj_pmudatainit_super(g, board_obj_ptr, ppmudata);
450 if (status != 0)
451 return status;
452
453 pvin_dev = (struct vin_device *)board_obj_ptr;
454 perf_pmu_data = (struct nv_pmu_clk_clk_vin_device_boardobj_set *)
455 ppmudata;
456
457 perf_pmu_data->id = pvin_dev->id;
458 perf_pmu_data->intercept = pvin_dev->intercept;
459 perf_pmu_data->volt_domain = pvin_dev->volt_domain;
460 perf_pmu_data->slope = pvin_dev->slope;
461 perf_pmu_data->flls_shared_mask = pvin_dev->flls_shared_mask;
462
463 gk20a_dbg_info(" Done");
464
465 return status;
466}