summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/volt/volt_rail.c
diff options
context:
space:
mode:
authorMahantesh Kumbar <mkumbar@nvidia.com>2016-09-19 01:37:46 -0400
committerDeepak Nibade <dnibade@nvidia.com>2016-12-27 04:56:50 -0500
commit173bdefc92e2e4ef8f1e7e6ead7f86e746bee935 (patch)
tree69d9a43a453e988c54927ade2f5ce04457eaf312 /drivers/gpu/nvgpu/volt/volt_rail.c
parentdb529935a5f50e9e683d44d2eb01d0d76a915792 (diff)
gpu: nvgpu: add support for voltage config
- changes to read voltage tables from VBIOS & create boardobj then send to pmu - Rail, Device & Policy objects are read from VBIOS & created boardobjs - RPC support to load, Set & get voltage. JIRA DNVGPU-122 Change-Id: I61621a514eef9c081a64c4ab066f01dfc28f8402 Signed-off-by: Mahantesh Kumbar <mkumbar@nvidia.com> Reviewed-on: http://git-master/r/1222774 (cherry picked from commit 9da86d8c2c547623cf5f38c89afeb3f5bb1667ac) Reviewed-on: http://git-master/r/1244656 GVS: Gerrit_Virtual_Submit Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com> Tested-by: Terje Bergstrom <tbergstrom@nvidia.com>
Diffstat (limited to 'drivers/gpu/nvgpu/volt/volt_rail.c')
-rw-r--r--drivers/gpu/nvgpu/volt/volt_rail.c438
1 files changed, 438 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/volt/volt_rail.c b/drivers/gpu/nvgpu/volt/volt_rail.c
new file mode 100644
index 00000000..87b85160
--- /dev/null
+++ b/drivers/gpu/nvgpu/volt/volt_rail.c
@@ -0,0 +1,438 @@
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 "include/bios.h"
16#include "boardobj/boardobjgrp.h"
17#include "boardobj/boardobjgrp_e32.h"
18#include "pmuif/gpmuifboardobj.h"
19#include "gm206/bios_gm206.h"
20#include "ctrl/ctrlvolt.h"
21#include "gk20a/pmu_gk20a.h"
22
23#include "pmuif/gpmuifperfvfe.h"
24#include "include/bios.h"
25#include "volt.h"
26
27u8 volt_rail_volt_domain_convert_to_idx(struct gk20a *g, u8 volt_domain)
28{
29 switch (g->perf_pmu.volt.volt_rail_metadata.volt_domain_hal) {
30 case CTRL_VOLT_DOMAIN_HAL_GP10X_SINGLE_RAIL:
31 if (volt_domain == CTRL_BOARDOBJ_IDX_INVALID)
32 return 0;
33 break;
34 case CTRL_VOLT_DOMAIN_HAL_GP10X_SPLIT_RAIL:
35 switch (volt_domain) {
36 case CTRL_VOLT_DOMAIN_LOGIC:
37 return 0;
38 case CTRL_VOLT_DOMAIN_SRAM:
39 return 1;
40 }
41 break;
42 }
43
44 return CTRL_BOARDOBJ_IDX_INVALID;
45}
46
47u32 volt_rail_volt_dev_register(struct gk20a *g, struct voltage_rail
48 *pvolt_rail, u8 volt_dev_idx, u8 operation_type)
49{
50 u32 status = 0;
51
52 if (operation_type == CTRL_VOLT_DEVICE_OPERATION_TYPE_DEFAULT) {
53 if (pvolt_rail->volt_dev_idx_default ==
54 CTRL_BOARDOBJ_IDX_INVALID) {
55 pvolt_rail->volt_dev_idx_default = volt_dev_idx;
56 } else {
57 status = -EINVAL;
58 goto exit;
59 }
60 } else {
61 goto exit;
62 }
63
64 status = boardobjgrpmask_bitset(&pvolt_rail->volt_dev_mask.super,
65 volt_dev_idx);
66
67exit:
68 if (status)
69 gk20a_err(dev_from_gk20a(g), "Failed to register VOLTAGE_DEVICE");
70
71 return status;
72}
73
74static u32 volt_rail_state_init(struct gk20a *g,
75 struct voltage_rail *pvolt_rail)
76{
77 u32 status = 0;
78 u32 i;
79
80 pvolt_rail->volt_dev_idx_default = CTRL_BOARDOBJ_IDX_INVALID;
81
82 for (i = 0; i < CTRL_VOLT_RAIL_VOLT_DELTA_MAX_ENTRIES; i++) {
83 pvolt_rail->volt_delta_uv[i] = NV_PMU_VOLT_VALUE_0V_IN_UV;
84 g->perf_pmu.volt.volt_rail_metadata.ext_rel_delta_uv[i] =
85 NV_PMU_VOLT_VALUE_0V_IN_UV;
86 }
87
88 pvolt_rail->volt_margin_limit_vfe_equ_mon_handle =
89 NV_PMU_PERF_RPC_VFE_EQU_MONITOR_COUNT_MAX;
90 pvolt_rail->rel_limit_vfe_equ_mon_handle =
91 NV_PMU_PERF_RPC_VFE_EQU_MONITOR_COUNT_MAX;
92 pvolt_rail->alt_rel_limit_vfe_equ_mon_handle =
93 NV_PMU_PERF_RPC_VFE_EQU_MONITOR_COUNT_MAX;
94 pvolt_rail->ov_limit_vfe_equ_mon_handle =
95 NV_PMU_PERF_RPC_VFE_EQU_MONITOR_COUNT_MAX;
96
97 status = boardobjgrpmask_e32_init(&pvolt_rail->volt_dev_mask, NULL);
98 if (status) {
99 gk20a_err(dev_from_gk20a(g),
100 "Failed to initialize BOARDOBJGRPMASK of VOLTAGE_DEVICEs");
101 }
102
103 return status;
104}
105
106static u32 volt_rail_init_pmudata_super(struct gk20a *g,
107 struct boardobj *board_obj_ptr, struct nv_pmu_boardobj *ppmudata)
108{
109 u32 status = 0;
110 struct voltage_rail *prail;
111 struct nv_pmu_volt_volt_rail_boardobj_set *rail_pmu_data;
112 u32 i;
113
114 gk20a_dbg_info("");
115
116 status = boardobj_pmudatainit_super(g, board_obj_ptr, ppmudata);
117 if (status)
118 return status;
119
120 prail = (struct voltage_rail *)board_obj_ptr;
121 rail_pmu_data = (struct nv_pmu_volt_volt_rail_boardobj_set *)
122 ppmudata;
123
124 rail_pmu_data->rel_limit_vfe_equ_idx = prail->rel_limit_vfe_equ_idx;
125 rail_pmu_data->alt_rel_limit_vfe_equ_idx =
126 prail->alt_rel_limit_vfe_equ_idx;
127 rail_pmu_data->ov_limit_vfe_equ_idx = prail->ov_limit_vfe_equ_idx;
128 rail_pmu_data->vmin_limit_vfe_equ_idx = prail->vmin_limit_vfe_equ_idx;
129 rail_pmu_data->volt_margin_limit_vfe_equ_idx =
130 prail->volt_margin_limit_vfe_equ_idx;
131 rail_pmu_data->pwr_equ_idx = prail->pwr_equ_idx;
132 rail_pmu_data->volt_dev_idx_default = prail->volt_dev_idx_default;
133
134 for (i = 0; i < CTRL_VOLT_RAIL_VOLT_DELTA_MAX_ENTRIES; i++) {
135 rail_pmu_data->volt_delta_uv[i] = prail->volt_delta_uv[i] +
136 g->perf_pmu.volt.volt_rail_metadata.ext_rel_delta_uv[i];
137 }
138
139 status = boardobjgrpmask_export(&prail->volt_dev_mask.super,
140 prail->volt_dev_mask.super.bitcount,
141 &rail_pmu_data->volt_dev_mask.super);
142 if (status)
143 gk20a_err(dev_from_gk20a(g),
144 "Failed to export BOARDOBJGRPMASK of VOLTAGE_DEVICEs");
145
146 gk20a_dbg_info("Done");
147
148 return status;
149}
150
151static struct voltage_rail *construct_volt_rail(struct gk20a *g, void *pargs)
152{
153 struct boardobj *board_obj_ptr = NULL;
154 struct voltage_rail *ptemp_rail = (struct voltage_rail *)pargs;
155 struct voltage_rail *board_obj_volt_rail_ptr = NULL;
156 u32 status;
157
158 gk20a_dbg_info("");
159 status = boardobj_construct_super(g, &board_obj_ptr,
160 sizeof(struct voltage_rail), pargs);
161 if (status)
162 return NULL;
163
164 board_obj_volt_rail_ptr = (struct voltage_rail *)board_obj_ptr;
165 /* override super class interface */
166 board_obj_ptr->pmudatainit = volt_rail_init_pmudata_super;
167
168 board_obj_volt_rail_ptr->boot_voltage_uv =
169 ptemp_rail->boot_voltage_uv;
170 board_obj_volt_rail_ptr->rel_limit_vfe_equ_idx =
171 ptemp_rail->rel_limit_vfe_equ_idx;
172 board_obj_volt_rail_ptr->alt_rel_limit_vfe_equ_idx =
173 ptemp_rail->alt_rel_limit_vfe_equ_idx;
174 board_obj_volt_rail_ptr->ov_limit_vfe_equ_idx =
175 ptemp_rail->ov_limit_vfe_equ_idx;
176 board_obj_volt_rail_ptr->pwr_equ_idx =
177 ptemp_rail->pwr_equ_idx;
178 board_obj_volt_rail_ptr->boot_volt_vfe_equ_idx =
179 ptemp_rail->boot_volt_vfe_equ_idx;
180 board_obj_volt_rail_ptr->vmin_limit_vfe_equ_idx =
181 ptemp_rail->vmin_limit_vfe_equ_idx;
182 board_obj_volt_rail_ptr->volt_margin_limit_vfe_equ_idx =
183 ptemp_rail->volt_margin_limit_vfe_equ_idx;
184
185 gk20a_dbg_info("Done");
186
187 return (struct voltage_rail *)board_obj_ptr;
188}
189
190u8 volt_rail_vbios_volt_domain_convert_to_internal(struct gk20a *g,
191 u8 vbios_volt_domain)
192{
193 switch (g->perf_pmu.volt.volt_rail_metadata.volt_domain_hal) {
194 case CTRL_VOLT_DOMAIN_HAL_GP10X_SINGLE_RAIL:
195 if (vbios_volt_domain == 0)
196 return CTRL_VOLT_DOMAIN_LOGIC;
197 break;
198 case CTRL_VOLT_DOMAIN_HAL_GP10X_SPLIT_RAIL:
199 switch (vbios_volt_domain) {
200 case 0:
201 return CTRL_VOLT_DOMAIN_LOGIC;
202 case 1:
203 return CTRL_VOLT_DOMAIN_SRAM;
204 }
205 break;
206 }
207
208 return CTRL_VOLT_DOMAIN_INVALID;
209}
210
211u32 volt_rail_pmu_setup(struct gk20a *g)
212{
213 u32 status;
214 struct boardobjgrp *pboardobjgrp = NULL;
215
216 gk20a_dbg_info("");
217
218 pboardobjgrp = &g->perf_pmu.volt.volt_rail_metadata.volt_rails.super;
219
220 if (!pboardobjgrp->bconstructed)
221 return -EINVAL;
222
223 status = pboardobjgrp->pmuinithandle(g, pboardobjgrp);
224
225 gk20a_dbg_info("Done");
226 return status;
227}
228
229static u32 volt_get_volt_rail_table(struct gk20a *g,
230 struct voltage_rail_metadata *pvolt_rail_metadata)
231{
232 u32 status = 0;
233 u8 *volt_rail_table_ptr = NULL;
234 struct voltage_rail *prail = NULL;
235 struct vbios_voltage_rail_table_1x_header header = { 0 };
236 struct vbios_voltage_rail_table_1x_entry entry = { 0 };
237 u8 i;
238 u8 volt_domain;
239 u8 *entry_ptr;
240 union rail_type {
241 struct boardobj board_obj;
242 struct voltage_rail volt_rail;
243 } rail_type_data;
244
245 if (g->ops.bios.get_perf_table_ptrs) {
246 volt_rail_table_ptr = (u8 *)g->ops.bios.get_perf_table_ptrs(g,
247 g->bios.perf_token, VOLTAGE_RAIL_TABLE);
248 if (volt_rail_table_ptr == NULL) {
249 status = -EINVAL;
250 goto done;
251 }
252 } else {
253 status = -EINVAL;
254 goto done;
255 }
256
257 memcpy(&header, volt_rail_table_ptr,
258 sizeof(struct vbios_voltage_rail_table_1x_header));
259
260 pvolt_rail_metadata->volt_domain_hal = (u8)header.volt_domain_hal;
261
262 for (i = 0; i < header.num_table_entries; i++) {
263 entry_ptr = (volt_rail_table_ptr + header.header_size +
264 (i * header.table_entry_size));
265
266 memset(&rail_type_data, 0x0, sizeof(rail_type_data));
267
268 memcpy(&entry, entry_ptr,
269 sizeof(struct vbios_voltage_rail_table_1x_entry));
270
271 volt_domain = volt_rail_vbios_volt_domain_convert_to_internal(g,
272 i);
273 if (volt_domain == CTRL_VOLT_DOMAIN_INVALID)
274 continue;
275
276 rail_type_data.board_obj.type = volt_domain;
277 rail_type_data.volt_rail.boot_voltage_uv =
278 (u32)entry.boot_voltage_uv;
279 rail_type_data.volt_rail.rel_limit_vfe_equ_idx =
280 (u8)entry.rel_limit_vfe_equ_idx;
281 rail_type_data.volt_rail.alt_rel_limit_vfe_equ_idx =
282 (u8)entry.alt_rel_limit_vfe_equidx;
283 rail_type_data.volt_rail.ov_limit_vfe_equ_idx =
284 (u8)entry.ov_limit_vfe_equ_idx;
285
286 if (header.table_entry_size >=
287 NV_VBIOS_VOLTAGE_RAIL_1X_ENTRY_SIZE_0B)
288 rail_type_data.volt_rail.volt_margin_limit_vfe_equ_idx =
289 (u8)entry.volt_margin_limit_vfe_equ_idx;
290 else
291 rail_type_data.volt_rail.volt_margin_limit_vfe_equ_idx =
292 CTRL_BOARDOBJ_IDX_INVALID;
293
294 if (header.table_entry_size >=
295 NV_VBIOS_VOLTAGE_RAIL_1X_ENTRY_SIZE_0A)
296 rail_type_data.volt_rail.vmin_limit_vfe_equ_idx =
297 (u8)entry.vmin_limit_vfe_equ_idx;
298 else
299 rail_type_data.volt_rail.vmin_limit_vfe_equ_idx =
300 CTRL_BOARDOBJ_IDX_INVALID;
301
302 if (header.table_entry_size >=
303 NV_VBIOS_VOLTAGE_RAIL_1X_ENTRY_SIZE_09)
304 rail_type_data.volt_rail.boot_volt_vfe_equ_idx =
305 (u8)entry.boot_volt_vfe_equ_idx;
306 else
307 rail_type_data.volt_rail.boot_volt_vfe_equ_idx =
308 CTRL_BOARDOBJ_IDX_INVALID;
309
310 if (header.table_entry_size >=
311 NV_VBIOS_VOLTAGE_RAIL_1X_ENTRY_SIZE_08)
312 rail_type_data.volt_rail.pwr_equ_idx =
313 (u8)entry.pwr_equ_idx;
314 else
315 rail_type_data.volt_rail.pwr_equ_idx =
316 CTRL_PMGR_PWR_EQUATION_INDEX_INVALID;
317
318 prail = construct_volt_rail(g, &rail_type_data);
319
320 status = boardobjgrp_objinsert(
321 &pvolt_rail_metadata->volt_rails.super,
322 (struct boardobj *)prail, i);
323 }
324
325done:
326 return status;
327}
328
329static u32 _volt_rail_devgrp_pmudata_instget(struct gk20a *g,
330 struct nv_pmu_boardobjgrp *pmuboardobjgrp, struct nv_pmu_boardobj
331 **ppboardobjpmudata, u8 idx)
332{
333 struct nv_pmu_volt_volt_rail_boardobj_grp_set *pgrp_set =
334 (struct nv_pmu_volt_volt_rail_boardobj_grp_set *)
335 pmuboardobjgrp;
336
337 gk20a_dbg_info("");
338
339 /*check whether pmuboardobjgrp has a valid boardobj in index*/
340 if (((u32)BIT(idx) &
341 pgrp_set->hdr.data.super.obj_mask.super.data[0]) == 0)
342 return -EINVAL;
343
344 *ppboardobjpmudata = (struct nv_pmu_boardobj *)
345 &pgrp_set->objects[idx].data.board_obj;
346 gk20a_dbg_info(" Done");
347 return 0;
348}
349
350static u32 _volt_rail_devgrp_pmustatus_instget(struct gk20a *g,
351 void *pboardobjgrppmu, struct nv_pmu_boardobj_query
352 **ppboardobjpmustatus, u8 idx)
353{
354 struct nv_pmu_volt_volt_rail_boardobj_grp_get_status *pgrp_get_status =
355 (struct nv_pmu_volt_volt_rail_boardobj_grp_get_status *)
356 pboardobjgrppmu;
357
358 /*check whether pmuboardobjgrp has a valid boardobj in index*/
359 if (((u32)BIT(idx) &
360 pgrp_get_status->hdr.data.super.obj_mask.super.data[0]) == 0)
361 return -EINVAL;
362
363 *ppboardobjpmustatus = (struct nv_pmu_boardobj_query *)
364 &pgrp_get_status->objects[idx].data.board_obj;
365 return 0;
366}
367
368u32 volt_rail_sw_setup(struct gk20a *g)
369{
370 u32 status = 0;
371 struct boardobjgrp *pboardobjgrp = NULL;
372 struct voltage_rail *pvolt_rail;
373 u8 i;
374
375 gk20a_dbg_info("");
376
377 status = boardobjgrpconstruct_e32(&g->perf_pmu.volt.volt_rail_metadata.
378 volt_rails);
379 if (status) {
380 gk20a_err(dev_from_gk20a(g),
381 "error creating boardobjgrp for volt rail, status - 0x%x",
382 status);
383 goto done;
384 }
385
386 pboardobjgrp = &g->perf_pmu.volt.volt_rail_metadata.volt_rails.super;
387
388 pboardobjgrp->pmudatainstget = _volt_rail_devgrp_pmudata_instget;
389 pboardobjgrp->pmustatusinstget = _volt_rail_devgrp_pmustatus_instget;
390
391 g->perf_pmu.volt.volt_rail_metadata.pct_delta =
392 NV_PMU_VOLT_VALUE_0V_IN_UV;
393
394 /* Obtain Voltage Rail Table from VBIOS */
395 status = volt_get_volt_rail_table(g, &g->perf_pmu.volt.
396 volt_rail_metadata);
397 if (status)
398 goto done;
399
400 /* Populate data for the VOLT_RAIL PMU interface */
401 BOARDOBJGRP_PMU_CONSTRUCT(pboardobjgrp, VOLT, VOLT_RAIL);
402
403 status = BOARDOBJGRP_PMU_CMD_GRP_SET_CONSTRUCT(g, pboardobjgrp,
404 volt, VOLT, volt_rail, VOLT_RAIL);
405 if (status) {
406 gk20a_err(dev_from_gk20a(g),
407 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
408 status);
409 goto done;
410 }
411
412 status = BOARDOBJGRP_PMU_CMD_GRP_GET_STATUS_CONSTRUCT(g,
413 &g->perf_pmu.volt.volt_rail_metadata.volt_rails.super,
414 volt, VOLT, volt_rail, VOLT_RAIL);
415 if (status) {
416 gk20a_err(dev_from_gk20a(g),
417 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
418 status);
419 goto done;
420 }
421
422 /* update calibration to fuse */
423 BOARDOBJGRP_FOR_EACH(&(g->perf_pmu.volt.volt_rail_metadata.
424 volt_rails.super),
425 struct voltage_rail *, pvolt_rail, i) {
426 status = volt_rail_state_init(g, pvolt_rail);
427 if (status) {
428 gk20a_err(dev_from_gk20a(g),
429 "Failure while executing RAIL's state init railIdx = %d",
430 i);
431 goto done;
432 }
433 }
434
435done:
436 gk20a_dbg_info(" done status %x", status);
437 return status;
438}