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