summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/volt
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/nvgpu/volt')
-rw-r--r--drivers/gpu/nvgpu/volt/volt.h39
-rw-r--r--drivers/gpu/nvgpu/volt/volt_dev.c589
-rw-r--r--drivers/gpu/nvgpu/volt/volt_dev.h78
-rw-r--r--drivers/gpu/nvgpu/volt/volt_pmu.c286
-rw-r--r--drivers/gpu/nvgpu/volt/volt_pmu.h32
-rw-r--r--drivers/gpu/nvgpu/volt/volt_policy.c361
-rw-r--r--drivers/gpu/nvgpu/volt/volt_policy.h73
-rw-r--r--drivers/gpu/nvgpu/volt/volt_rail.c439
-rw-r--r--drivers/gpu/nvgpu/volt/volt_rail.h88
9 files changed, 1985 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/volt/volt.h b/drivers/gpu/nvgpu/volt/volt.h
new file mode 100644
index 00000000..482172bf
--- /dev/null
+++ b/drivers/gpu/nvgpu/volt/volt.h
@@ -0,0 +1,39 @@
1/*
2* Copyright (c) 2016, 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#ifndef _VOLT_H_
24#define _VOLT_H_
25
26#include "volt_rail.h"
27#include "volt_dev.h"
28#include "volt_policy.h"
29#include "volt_pmu.h"
30
31#define VOLTAGE_DESCRIPTOR_TABLE_ENTRY_INVALID 0xFF
32
33struct obj_volt {
34 struct voltage_rail_metadata volt_rail_metadata;
35 struct voltage_device_metadata volt_dev_metadata;
36 struct voltage_policy_metadata volt_policy_metadata;
37};
38
39#endif /* DRIVERS_GPU_NVGPU_VOLT_VOLT_H_ */
diff --git a/drivers/gpu/nvgpu/volt/volt_dev.c b/drivers/gpu/nvgpu/volt/volt_dev.c
new file mode 100644
index 00000000..6ad658b8
--- /dev/null
+++ b/drivers/gpu/nvgpu/volt/volt_dev.c
@@ -0,0 +1,589 @@
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/sort.h>
24#include <nvgpu/pmuif/nvgpu_gpmu_cmdif.h>
25#include <nvgpu/bios.h>
26#include <nvgpu/kmem.h>
27
28#include "gk20a/gk20a.h"
29#include "gp106/bios_gp106.h"
30
31#include "boardobj/boardobjgrp.h"
32#include "boardobj/boardobjgrp_e32.h"
33#include "ctrl/ctrlvolt.h"
34
35#include "volt.h"
36
37#define VOLT_DEV_PWM_VOLTAGE_STEPS_INVALID 0
38#define VOLT_DEV_PWM_VOLTAGE_STEPS_DEFAULT 1
39
40static u32 volt_device_pmu_data_init_super(struct gk20a *g,
41 struct boardobj *pboard_obj, struct nv_pmu_boardobj *ppmudata)
42{
43 u32 status;
44 struct voltage_device *pdev;
45 struct nv_pmu_volt_volt_device_boardobj_set *pset;
46
47 status = boardobj_pmudatainit_super(g, pboard_obj, ppmudata);
48 if (status)
49 return status;
50
51 pdev = (struct voltage_device *)pboard_obj;
52 pset = (struct nv_pmu_volt_volt_device_boardobj_set *)ppmudata;
53
54 pset->switch_delay_us = pdev->switch_delay_us;
55 pset->voltage_min_uv = pdev->voltage_min_uv;
56 pset->voltage_max_uv = pdev->voltage_max_uv;
57 pset->volt_step_uv = pdev->volt_step_uv;
58
59 return status;
60}
61
62static u32 volt_device_pmu_data_init_pwm(struct gk20a *g,
63 struct boardobj *pboard_obj, struct nv_pmu_boardobj *ppmudata)
64{
65 u32 status = 0;
66 struct voltage_device_pwm *pdev;
67 struct nv_pmu_volt_volt_device_pwm_boardobj_set *pset;
68
69 status = volt_device_pmu_data_init_super(g, pboard_obj, ppmudata);
70 if (status)
71 return status;
72
73 pdev = (struct voltage_device_pwm *)pboard_obj;
74 pset = (struct nv_pmu_volt_volt_device_pwm_boardobj_set *)ppmudata;
75
76 pset->raw_period = pdev->raw_period;
77 pset->voltage_base_uv = pdev->voltage_base_uv;
78 pset->voltage_offset_scale_uv = pdev->voltage_offset_scale_uv;
79 pset->pwm_source = pdev->source;
80
81 return status;
82}
83
84static u32 construct_volt_device(struct gk20a *g,
85 struct boardobj **ppboardobj, u16 size, void *pargs)
86{
87 struct voltage_device *ptmp_dev = (struct voltage_device *)pargs;
88 struct voltage_device *pvolt_dev = NULL;
89 u32 status = 0;
90
91 status = boardobj_construct_super(g, ppboardobj, size, pargs);
92 if (status)
93 return status;
94
95 pvolt_dev = (struct voltage_device *)*ppboardobj;
96
97 pvolt_dev->volt_domain = ptmp_dev->volt_domain;
98 pvolt_dev->i2c_dev_idx = ptmp_dev->i2c_dev_idx;
99 pvolt_dev->switch_delay_us = ptmp_dev->switch_delay_us;
100 pvolt_dev->rsvd_0 = VOLTAGE_DESCRIPTOR_TABLE_ENTRY_INVALID;
101 pvolt_dev->rsvd_1 =
102 VOLTAGE_DESCRIPTOR_TABLE_ENTRY_INVALID;
103 pvolt_dev->operation_type = ptmp_dev->operation_type;
104 pvolt_dev->voltage_min_uv = ptmp_dev->voltage_min_uv;
105 pvolt_dev->voltage_max_uv = ptmp_dev->voltage_max_uv;
106
107 pvolt_dev->super.pmudatainit = volt_device_pmu_data_init_super;
108
109 return status;
110}
111
112static u32 construct_pwm_volt_device(struct gk20a *g,
113 struct boardobj **ppboardobj,
114 u16 size, void *pargs)
115{
116 struct boardobj *pboard_obj = NULL;
117 struct voltage_device_pwm *ptmp_dev =
118 (struct voltage_device_pwm *)pargs;
119 struct voltage_device_pwm *pdev = NULL;
120 u32 status = 0;
121
122 status = construct_volt_device(g, ppboardobj, size, pargs);
123 if (status)
124 return status;
125
126 pboard_obj = (*ppboardobj);
127 pdev = (struct voltage_device_pwm *)*ppboardobj;
128
129 pboard_obj->pmudatainit = volt_device_pmu_data_init_pwm;
130
131 /* Set VOLTAGE_DEVICE_PWM-specific parameters */
132 pdev->voltage_base_uv = ptmp_dev->voltage_base_uv;
133 pdev->voltage_offset_scale_uv = ptmp_dev->voltage_offset_scale_uv;
134 pdev->source = ptmp_dev->source;
135 pdev->raw_period = ptmp_dev->raw_period;
136
137 return status;
138}
139
140
141static struct voltage_device_entry *volt_dev_construct_dev_entry_pwm(
142 struct gk20a *g,
143 u32 voltage_uv, void *pargs)
144{
145 struct voltage_device_pwm_entry *pentry = NULL;
146 struct voltage_device_pwm_entry *ptmp_entry =
147 (struct voltage_device_pwm_entry *)pargs;
148
149 pentry = nvgpu_kzalloc(g, sizeof(struct voltage_device_pwm_entry));
150 if (pentry == NULL)
151 return NULL;
152
153 memset(pentry, 0, sizeof(struct voltage_device_pwm_entry));
154
155 pentry->super.voltage_uv = voltage_uv;
156 pentry->duty_cycle = ptmp_entry->duty_cycle;
157
158 return (struct voltage_device_entry *)pentry;
159}
160
161static u8 volt_dev_operation_type_convert(u8 vbios_type)
162{
163 switch (vbios_type) {
164 case NV_VBIOS_VDT_1X_ENTRY_PARAM1_PSV_OPERATION_TYPE_DEFAULT:
165 return CTRL_VOLT_DEVICE_OPERATION_TYPE_DEFAULT;
166
167 case NV_VBIOS_VDT_1X_ENTRY_PARAM1_PSV_OPERATION_TYPE_LPWR_STEADY_STATE:
168 return CTRL_VOLT_DEVICE_OPERATION_TYPE_LPWR_STEADY_STATE;
169
170 case NV_VBIOS_VDT_1X_ENTRY_PARAM1_PSV_OPERATION_TYPE_LPWR_SLEEP_STATE:
171 return CTRL_VOLT_DEVICE_OPERATION_TYPE_LPWR_SLEEP_STATE;
172 }
173
174 return CTRL_VOLT_DEVICE_OPERATION_TYPE_INVALID;
175}
176
177static struct voltage_device *volt_volt_device_construct(struct gk20a *g,
178 void *pargs)
179{
180 struct boardobj *pboard_obj = NULL;
181
182 if (BOARDOBJ_GET_TYPE(pargs) == CTRL_VOLT_DEVICE_TYPE_PWM) {
183 u32 status = construct_pwm_volt_device(g, &pboard_obj,
184 sizeof(struct voltage_device_pwm), pargs);
185 if (status) {
186 nvgpu_err(g,
187 " Could not allocate memory for VOLTAGE_DEVICE type (%x).",
188 BOARDOBJ_GET_TYPE(pargs));
189 pboard_obj = NULL;
190 }
191 }
192
193 return (struct voltage_device *)pboard_obj;
194}
195
196static u32 volt_get_voltage_device_table_1x_psv(struct gk20a *g,
197 struct vbios_voltage_device_table_1x_entry *p_bios_entry,
198 struct voltage_device_metadata *p_Volt_Device_Meta_Data,
199 u8 entry_Idx)
200{
201 u32 status = 0;
202 u32 entry_cnt = 0;
203 struct voltage_device *pvolt_dev = NULL;
204 struct voltage_device_pwm *pvolt_dev_pwm = NULL;
205 struct voltage_device_pwm *ptmp_dev = NULL;
206 u32 duty_cycle;
207 u32 frequency_hz;
208 u32 voltage_uv;
209 u8 ext_dev_idx;
210 u8 steps;
211 u8 volt_domain = 0;
212 struct voltage_device_pwm_entry pwm_entry = { { 0 } };
213
214 ptmp_dev = nvgpu_kzalloc(g, sizeof(struct voltage_device_pwm));
215 if (ptmp_dev == NULL)
216 return -ENOMEM;
217
218 frequency_hz = (u32)BIOS_GET_FIELD(p_bios_entry->param0,
219 NV_VBIOS_VDT_1X_ENTRY_PARAM0_PSV_INPUT_FREQUENCY);
220
221 ext_dev_idx = (u8)BIOS_GET_FIELD(p_bios_entry->param0,
222 NV_VBIOS_VDT_1X_ENTRY_PARAM0_PSV_EXT_DEVICE_INDEX);
223
224 ptmp_dev->super.operation_type = volt_dev_operation_type_convert(
225 (u8)BIOS_GET_FIELD(p_bios_entry->param1,
226 NV_VBIOS_VDT_1X_ENTRY_PARAM1_PSV_OPERATION_TYPE));
227
228 if (ptmp_dev->super.operation_type ==
229 CTRL_VOLT_DEVICE_OPERATION_TYPE_INVALID) {
230 nvgpu_err(g, " Invalid Voltage Device Operation Type.");
231
232 status = -EINVAL;
233 goto done;
234 }
235
236 ptmp_dev->super.voltage_min_uv =
237 (u32)BIOS_GET_FIELD(p_bios_entry->param1,
238 NV_VBIOS_VDT_1X_ENTRY_PARAM1_PSV_VOLTAGE_MINIMUM);
239
240 ptmp_dev->super.voltage_max_uv =
241 (u32)BIOS_GET_FIELD(p_bios_entry->param2,
242 NV_VBIOS_VDT_1X_ENTRY_PARAM2_PSV_VOLTAGE_MAXIMUM);
243
244 ptmp_dev->voltage_base_uv = BIOS_GET_FIELD(p_bios_entry->param3,
245 NV_VBIOS_VDT_1X_ENTRY_PARAM3_PSV_VOLTAGE_BASE);
246
247 steps = (u8)BIOS_GET_FIELD(p_bios_entry->param3,
248 NV_VBIOS_VDT_1X_ENTRY_PARAM3_PSV_VOLTAGE_STEPS);
249 if (steps == VOLT_DEV_PWM_VOLTAGE_STEPS_INVALID)
250 steps = VOLT_DEV_PWM_VOLTAGE_STEPS_DEFAULT;
251
252 ptmp_dev->voltage_offset_scale_uv =
253 BIOS_GET_FIELD(p_bios_entry->param4,
254 NV_VBIOS_VDT_1X_ENTRY_PARAM4_PSV_OFFSET_SCALE);
255
256 volt_domain = volt_rail_vbios_volt_domain_convert_to_internal(g,
257 (u8)p_bios_entry->volt_domain);
258 if (volt_domain == CTRL_VOLT_DOMAIN_INVALID) {
259 nvgpu_err(g, "invalid voltage domain = %d",
260 (u8)p_bios_entry->volt_domain);
261 status = -EINVAL;
262 goto done;
263 }
264
265 if (ptmp_dev->super.operation_type ==
266 CTRL_VOLT_DEVICE_OPERATION_TYPE_DEFAULT) {
267 if (volt_domain == CTRL_VOLT_DOMAIN_LOGIC)
268 ptmp_dev->source =
269 NV_PMU_PMGR_PWM_SOURCE_THERM_VID_PWM_0;
270 if (volt_domain == CTRL_VOLT_DOMAIN_SRAM)
271 ptmp_dev->source =
272 NV_PMU_PMGR_PWM_SOURCE_THERM_VID_PWM_1;
273 ptmp_dev->raw_period =
274 g->ops.clk.get_crystal_clk_hz(g) / frequency_hz;
275 } else if (ptmp_dev->super.operation_type ==
276 CTRL_VOLT_DEVICE_OPERATION_TYPE_LPWR_STEADY_STATE) {
277 ptmp_dev->source = NV_PMU_PMGR_PWM_SOURCE_RSVD_0;
278 ptmp_dev->raw_period = 0;
279 } else if (ptmp_dev->super.operation_type ==
280 CTRL_VOLT_DEVICE_OPERATION_TYPE_LPWR_SLEEP_STATE) {
281 ptmp_dev->source = NV_PMU_PMGR_PWM_SOURCE_RSVD_1;
282 ptmp_dev->raw_period = 0;
283 }
284
285 /* Initialize data for parent class. */
286 ptmp_dev->super.super.type = CTRL_VOLT_DEVICE_TYPE_PWM;
287 ptmp_dev->super.volt_domain = volt_domain;
288 ptmp_dev->super.i2c_dev_idx = ext_dev_idx;
289 ptmp_dev->super.switch_delay_us = (u16)p_bios_entry->settle_time_us;
290
291 pvolt_dev = volt_volt_device_construct(g, ptmp_dev);
292 if (pvolt_dev == NULL) {
293 nvgpu_err(g, " Failure to construct VOLTAGE_DEVICE object.");
294
295 status = -EINVAL;
296 goto done;
297 }
298
299 status = boardobjgrp_objinsert(
300 &p_Volt_Device_Meta_Data->volt_devices.super,
301 (struct boardobj *)pvolt_dev, entry_Idx);
302 if (status) {
303 nvgpu_err(g,
304 "could not add VOLTAGE_DEVICE for entry %d into boardobjgrp ",
305 entry_Idx);
306 goto done;
307 }
308
309 pvolt_dev_pwm = (struct voltage_device_pwm *)pvolt_dev;
310
311 duty_cycle = 0;
312 do {
313 voltage_uv = (u32)(pvolt_dev_pwm->voltage_base_uv +
314 (s32)((((s64)((s32)duty_cycle)) *
315 pvolt_dev_pwm->voltage_offset_scale_uv)
316 / ((s64)((s32) pvolt_dev_pwm->raw_period))));
317
318 /* Skip creating entry for invalid voltage. */
319 if ((voltage_uv >= pvolt_dev_pwm->super.voltage_min_uv) &&
320 (voltage_uv <= pvolt_dev_pwm->super.voltage_max_uv)) {
321 if (pvolt_dev_pwm->voltage_offset_scale_uv < 0)
322 pwm_entry.duty_cycle =
323 pvolt_dev_pwm->raw_period - duty_cycle;
324 else
325 pwm_entry.duty_cycle = duty_cycle;
326
327 /* Check if there is room left in the voltage table. */
328 if (entry_cnt == VOLTAGE_TABLE_MAX_ENTRIES) {
329 nvgpu_err(g, "Voltage table is full");
330 status = -EINVAL;
331 goto done;
332 }
333
334 pvolt_dev->pentry[entry_cnt] =
335 volt_dev_construct_dev_entry_pwm(g,
336 voltage_uv, &pwm_entry);
337 if (pvolt_dev->pentry[entry_cnt] == NULL) {
338 nvgpu_err(g,
339 " Error creating voltage_device_pwm_entry!");
340 status = -EINVAL;
341 goto done;
342 }
343
344 entry_cnt++;
345 }
346
347 /* Obtain next value after the specified steps. */
348 duty_cycle = duty_cycle + (u32)steps;
349
350 /* Cap duty cycle to PWM period. */
351 if (duty_cycle > pvolt_dev_pwm->raw_period)
352 duty_cycle = pvolt_dev_pwm->raw_period;
353
354 } while (duty_cycle < pvolt_dev_pwm->raw_period);
355
356done:
357 if (pvolt_dev != NULL)
358 pvolt_dev->num_entries = entry_cnt;
359
360 nvgpu_kfree(g, ptmp_dev);
361 return status;
362}
363
364static u32 volt_get_volt_devices_table(struct gk20a *g,
365 struct voltage_device_metadata *pvolt_device_metadata)
366{
367 u32 status = 0;
368 u8 *volt_device_table_ptr = NULL;
369 struct vbios_voltage_device_table_1x_header header = { 0 };
370 struct vbios_voltage_device_table_1x_entry entry = { 0 };
371 u8 entry_idx;
372 u8 *entry_offset;
373
374 volt_device_table_ptr = (u8 *)nvgpu_bios_get_perf_table_ptrs(g,
375 g->bios.perf_token, VOLTAGE_DEVICE_TABLE);
376 if (volt_device_table_ptr == NULL) {
377 status = -EINVAL;
378 goto done;
379 }
380
381 memcpy(&header, volt_device_table_ptr,
382 sizeof(struct vbios_voltage_device_table_1x_header));
383
384 /* Read in the entries. */
385 for (entry_idx = 0; entry_idx < header.num_table_entries; entry_idx++) {
386 entry_offset = (volt_device_table_ptr + header.header_size +
387 (entry_idx * header.table_entry_size));
388
389 memcpy(&entry, entry_offset,
390 sizeof(struct vbios_voltage_device_table_1x_entry));
391
392 if (entry.type == NV_VBIOS_VOLTAGE_DEVICE_1X_ENTRY_TYPE_PSV)
393 status = volt_get_voltage_device_table_1x_psv(g,
394 &entry, pvolt_device_metadata,
395 entry_idx);
396 }
397
398done:
399 return status;
400}
401
402static u32 _volt_device_devgrp_pmudata_instget(struct gk20a *g,
403 struct nv_pmu_boardobjgrp *pmuboardobjgrp,
404 struct nv_pmu_boardobj **ppboardobjpmudata, u8 idx)
405{
406 struct nv_pmu_volt_volt_device_boardobj_grp_set *pgrp_set =
407 (struct nv_pmu_volt_volt_device_boardobj_grp_set *)
408 pmuboardobjgrp;
409
410 gk20a_dbg_info("");
411
412 /*check whether pmuboardobjgrp has a valid boardobj in index*/
413 if (((u32)BIT(idx) &
414 pgrp_set->hdr.data.super.obj_mask.super.data[0]) == 0)
415 return -EINVAL;
416
417 *ppboardobjpmudata = (struct nv_pmu_boardobj *)
418 &pgrp_set->objects[idx].data.board_obj;
419 gk20a_dbg_info("Done");
420 return 0;
421}
422
423static u32 _volt_device_devgrp_pmustatus_instget(struct gk20a *g,
424 void *pboardobjgrppmu,
425 struct nv_pmu_boardobj_query **ppboardobjpmustatus, u8 idx)
426{
427 struct nv_pmu_volt_volt_device_boardobj_grp_get_status *pgrp_get_status
428 = (struct nv_pmu_volt_volt_device_boardobj_grp_get_status *)
429 pboardobjgrppmu;
430
431 /*check whether pmuboardobjgrp has a valid boardobj in index*/
432 if (((u32)BIT(idx) &
433 pgrp_get_status->hdr.data.super.obj_mask.super.data[0]) == 0)
434 return -EINVAL;
435
436 *ppboardobjpmustatus = (struct nv_pmu_boardobj_query *)
437 &pgrp_get_status->objects[idx].data.board_obj;
438 return 0;
439}
440
441static int volt_device_volt_cmp(const void *a, const void *b)
442{
443 const struct voltage_device_entry *a_entry = *(const struct voltage_device_entry **)a;
444 const struct voltage_device_entry *b_entry = *(const struct voltage_device_entry **)b;
445
446 return (int)a_entry->voltage_uv - (int)b_entry->voltage_uv;
447}
448
449static u32 volt_device_state_init(struct gk20a *g,
450 struct voltage_device *pvolt_dev)
451{
452 u32 status = 0;
453 struct voltage_rail *pRail = NULL;
454 u8 rail_idx = 0;
455
456 sort(pvolt_dev->pentry, pvolt_dev->num_entries,
457 sizeof(*pvolt_dev->pentry), volt_device_volt_cmp,
458 NULL);
459
460 /* Initialize VOLT_DEVICE step size. */
461 if (pvolt_dev->num_entries <= VOLTAGE_TABLE_MAX_ENTRIES_ONE)
462 pvolt_dev->volt_step_uv = NV_PMU_VOLT_VALUE_0V_IN_UV;
463 else
464 pvolt_dev->volt_step_uv = (pvolt_dev->pentry[1]->voltage_uv -
465 pvolt_dev->pentry[0]->voltage_uv);
466
467 /* Build VOLT_RAIL SW state from VOLT_DEVICE SW state. */
468 /* If VOLT_RAIL isn't supported, exit. */
469 if (VOLT_RAIL_VOLT_3X_SUPPORTED(&g->perf_pmu.volt)) {
470 rail_idx = volt_rail_volt_domain_convert_to_idx(g,
471 pvolt_dev->volt_domain);
472 if (rail_idx == CTRL_BOARDOBJ_IDX_INVALID) {
473 nvgpu_err(g,
474 " could not convert voltage domain to rail index.");
475 status = -EINVAL;
476 goto done;
477 }
478
479 pRail = VOLT_GET_VOLT_RAIL(&g->perf_pmu.volt, rail_idx);
480 if (pRail == NULL) {
481 nvgpu_err(g,
482 "could not obtain ptr to rail object from rail index");
483 status = -EINVAL;
484 goto done;
485 }
486
487 status = volt_rail_volt_dev_register(g, pRail,
488 BOARDOBJ_GET_IDX(pvolt_dev), pvolt_dev->operation_type);
489 if (status) {
490 nvgpu_err(g,
491 "Failed to register the device with rail obj");
492 goto done;
493 }
494 }
495
496done:
497 if (status)
498 nvgpu_err(g, "Error in building rail sw state device sw");
499
500 return status;
501}
502
503u32 volt_dev_pmu_setup(struct gk20a *g)
504{
505 u32 status;
506 struct boardobjgrp *pboardobjgrp = NULL;
507
508 gk20a_dbg_info("");
509
510 pboardobjgrp = &g->perf_pmu.volt.volt_dev_metadata.volt_devices.super;
511
512 if (!pboardobjgrp->bconstructed)
513 return -EINVAL;
514
515 status = pboardobjgrp->pmuinithandle(g, pboardobjgrp);
516
517 gk20a_dbg_info("Done");
518 return status;
519}
520
521u32 volt_dev_sw_setup(struct gk20a *g)
522{
523 u32 status = 0;
524 struct boardobjgrp *pboardobjgrp = NULL;
525 struct voltage_device *pvolt_device;
526 u8 i;
527
528 gk20a_dbg_info("");
529
530 status = boardobjgrpconstruct_e32(g,
531 &g->perf_pmu.volt.volt_dev_metadata.volt_devices);
532 if (status) {
533 nvgpu_err(g,
534 "error creating boardobjgrp for volt rail, status - 0x%x",
535 status);
536 goto done;
537 }
538
539 pboardobjgrp = &g->perf_pmu.volt.volt_dev_metadata.volt_devices.super;
540
541 pboardobjgrp->pmudatainstget = _volt_device_devgrp_pmudata_instget;
542 pboardobjgrp->pmustatusinstget = _volt_device_devgrp_pmustatus_instget;
543
544 /* Obtain Voltage Rail Table from VBIOS */
545 status = volt_get_volt_devices_table(g, &g->perf_pmu.volt.
546 volt_dev_metadata);
547 if (status)
548 goto done;
549
550 /* Populate data for the VOLT_RAIL PMU interface */
551 BOARDOBJGRP_PMU_CONSTRUCT(pboardobjgrp, VOLT, VOLT_DEVICE);
552
553 status = BOARDOBJGRP_PMU_CMD_GRP_SET_CONSTRUCT(g, pboardobjgrp,
554 volt, VOLT, volt_device, VOLT_DEVICE);
555 if (status) {
556 nvgpu_err(g,
557 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
558 status);
559 goto done;
560 }
561
562 status = BOARDOBJGRP_PMU_CMD_GRP_GET_STATUS_CONSTRUCT(g,
563 &g->perf_pmu.volt.volt_dev_metadata.volt_devices.super,
564 volt, VOLT, volt_device, VOLT_DEVICE);
565 if (status) {
566 nvgpu_err(g,
567 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
568 status);
569 goto done;
570 }
571
572 /* update calibration to fuse */
573 BOARDOBJGRP_FOR_EACH(&(g->perf_pmu.volt.volt_dev_metadata.volt_devices.
574 super),
575 struct voltage_device *, pvolt_device, i) {
576 status = volt_device_state_init(g, pvolt_device);
577 if (status) {
578 nvgpu_err(g,
579 "failure while executing devices's state init interface");
580 nvgpu_err(g,
581 " railIdx = %d, status = 0x%x", i, status);
582 goto done;
583 }
584 }
585
586done:
587 gk20a_dbg_info(" done status %x", status);
588 return status;
589}
diff --git a/drivers/gpu/nvgpu/volt/volt_dev.h b/drivers/gpu/nvgpu/volt/volt_dev.h
new file mode 100644
index 00000000..a3dc8cf6
--- /dev/null
+++ b/drivers/gpu/nvgpu/volt/volt_dev.h
@@ -0,0 +1,78 @@
1/*
2* Copyright (c) 2016, 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#ifndef _VOLTDEV_H_
25#define _VOLTDEV_H_
26
27#include "boardobj/boardobj.h"
28#include "boardobj/boardobjgrp.h"
29#include "ctrl/ctrlvolt.h"
30
31#define VOLTAGE_TABLE_MAX_ENTRIES_ONE 1
32#define VOLTAGE_TABLE_MAX_ENTRIES 256
33
34struct voltage_device {
35 struct boardobj super;
36 u8 volt_domain;
37 u8 i2c_dev_idx;
38 u32 switch_delay_us;
39 u32 num_entries;
40 struct voltage_device_entry *pentry[VOLTAGE_TABLE_MAX_ENTRIES];
41 struct voltage_device_entry *pcurr_entry;
42 u8 rsvd_0;
43 u8 rsvd_1;
44 u8 operation_type;
45 u32 voltage_min_uv;
46 u32 voltage_max_uv;
47 u32 volt_step_uv;
48};
49
50struct voltage_device_entry {
51 u32 voltage_uv;
52};
53
54struct voltage_device_metadata {
55 struct boardobjgrp_e32 volt_devices;
56};
57
58/*!
59 * Extends VOLTAGE_DEVICE providing attributes specific to PWM controllers.
60 */
61struct voltage_device_pwm {
62 struct voltage_device super;
63 s32 voltage_base_uv;
64 s32 voltage_offset_scale_uv;
65 enum nv_pmu_pmgr_pwm_source source;
66 u32 raw_period;
67};
68
69struct voltage_device_pwm_entry {
70 struct voltage_device_entry super;
71 u32 duty_cycle;
72};
73/* PWM end */
74
75u32 volt_dev_sw_setup(struct gk20a *g);
76u32 volt_dev_pmu_setup(struct gk20a *g);
77
78#endif /* _VOLTDEV_H_ */
diff --git a/drivers/gpu/nvgpu/volt/volt_pmu.c b/drivers/gpu/nvgpu/volt/volt_pmu.c
new file mode 100644
index 00000000..915db9a7
--- /dev/null
+++ b/drivers/gpu/nvgpu/volt/volt_pmu.c
@@ -0,0 +1,286 @@
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/pmu.h>
24#include <nvgpu/pmuif/nvgpu_gpmu_cmdif.h>
25
26#include "gk20a/gk20a.h"
27#include "boardobj/boardobjgrp.h"
28#include "boardobj/boardobjgrp_e32.h"
29#include "gp106/bios_gp106.h"
30#include "ctrl/ctrlvolt.h"
31#include "ctrl/ctrlperf.h"
32
33#include "volt.h"
34
35#define RAIL_COUNT 2
36
37struct volt_rpc_pmucmdhandler_params {
38 struct nv_pmu_volt_rpc *prpc_call;
39 u32 success;
40};
41
42static void volt_rpc_pmucmdhandler(struct gk20a *g, struct pmu_msg *msg,
43 void *param, u32 handle, u32 status)
44{
45 struct volt_rpc_pmucmdhandler_params *phandlerparams =
46 (struct volt_rpc_pmucmdhandler_params *)param;
47
48 gk20a_dbg_info("");
49
50 if (msg->msg.volt.msg_type != NV_PMU_VOLT_MSG_ID_RPC) {
51 nvgpu_err(g, "unsupported msg for VOLT RPC %x",
52 msg->msg.volt.msg_type);
53 return;
54 }
55
56 if (phandlerparams->prpc_call->b_supported)
57 phandlerparams->success = 1;
58}
59
60
61static u32 volt_pmu_rpc_execute(struct gk20a *g,
62 struct nv_pmu_volt_rpc *prpc_call)
63{
64 struct pmu_cmd cmd;
65 struct pmu_msg msg;
66 struct pmu_payload payload;
67 u32 status = 0;
68 u32 seqdesc;
69 struct volt_rpc_pmucmdhandler_params handler;
70
71 memset(&payload, 0, sizeof(struct pmu_payload));
72 memset(&cmd, 0, sizeof(struct pmu_cmd));
73 memset(&msg, 0, sizeof(struct pmu_msg));
74 memset(&handler, 0, sizeof(struct volt_rpc_pmucmdhandler_params));
75
76 cmd.hdr.unit_id = PMU_UNIT_VOLT;
77 cmd.hdr.size = (u32)sizeof(struct nv_pmu_volt_cmd) +
78 (u32)sizeof(struct pmu_hdr);
79 cmd.cmd.volt.cmd_type = NV_PMU_VOLT_CMD_ID_RPC;
80 msg.hdr.size = sizeof(struct pmu_msg);
81
82 payload.in.buf = (u8 *)prpc_call;
83 payload.in.size = (u32)sizeof(struct nv_pmu_volt_rpc);
84 payload.in.fb_size = PMU_CMD_SUBMIT_PAYLOAD_PARAMS_FB_SIZE_UNUSED;
85 payload.in.offset = NV_PMU_VOLT_CMD_RPC_ALLOC_OFFSET;
86
87 payload.out.buf = (u8 *)prpc_call;
88 payload.out.size = (u32)sizeof(struct nv_pmu_volt_rpc);
89 payload.out.fb_size = PMU_CMD_SUBMIT_PAYLOAD_PARAMS_FB_SIZE_UNUSED;
90 payload.out.offset = NV_PMU_VOLT_MSG_RPC_ALLOC_OFFSET;
91
92 handler.prpc_call = prpc_call;
93 handler.success = 0;
94
95 status = nvgpu_pmu_cmd_post(g, &cmd, NULL, &payload,
96 PMU_COMMAND_QUEUE_LPQ,
97 volt_rpc_pmucmdhandler, (void *)&handler,
98 &seqdesc, ~0);
99 if (status) {
100 nvgpu_err(g, "unable to post volt RPC cmd %x",
101 cmd.cmd.volt.cmd_type);
102 goto volt_pmu_rpc_execute;
103 }
104
105 pmu_wait_message_cond(&g->pmu,
106 gk20a_get_gr_idle_timeout(g),
107 &handler.success, 1);
108
109 if (handler.success == 0) {
110 status = -EINVAL;
111 nvgpu_err(g, "rpc call to volt failed");
112 }
113
114volt_pmu_rpc_execute:
115 return status;
116}
117
118u32 volt_pmu_send_load_cmd_to_pmu(struct gk20a *g)
119{
120 struct nv_pmu_volt_rpc rpc_call = { 0 };
121 u32 status = 0;
122
123 rpc_call.function = NV_PMU_VOLT_RPC_ID_LOAD;
124
125 status = volt_pmu_rpc_execute(g, &rpc_call);
126 if (status)
127 nvgpu_err(g,
128 "Error while executing LOAD RPC: status = 0x%08x.",
129 status);
130
131 return status;
132}
133
134static u32 volt_rail_get_voltage(struct gk20a *g,
135 u8 volt_domain, u32 *pvoltage_uv)
136{
137 struct nv_pmu_volt_rpc rpc_call = { 0 };
138 u32 status = 0;
139 u8 rail_idx;
140
141 rail_idx = volt_rail_volt_domain_convert_to_idx(g, volt_domain);
142 if ((rail_idx == CTRL_VOLT_RAIL_INDEX_INVALID) ||
143 (!VOLT_RAIL_INDEX_IS_VALID(&g->perf_pmu.volt, rail_idx))) {
144 nvgpu_err(g,
145 "failed: volt_domain = %d, voltage rail table = %d.",
146 volt_domain, rail_idx);
147 return -EINVAL;
148 }
149
150 /* Set RPC parameters. */
151 rpc_call.function = NV_PMU_VOLT_RPC_ID_VOLT_RAIL_GET_VOLTAGE;
152 rpc_call.params.volt_rail_get_voltage.rail_idx = rail_idx;
153
154 /* Execute the voltage get request via PMU RPC. */
155 status = volt_pmu_rpc_execute(g, &rpc_call);
156 if (status) {
157 nvgpu_err(g,
158 "Error while executing volt_rail_get_voltage rpc");
159 return status;
160 }
161
162 /* Copy out the current voltage. */
163 *pvoltage_uv = rpc_call.params.volt_rail_get_voltage.voltage_uv;
164
165 return status;
166}
167
168
169static u32 volt_policy_set_voltage(struct gk20a *g, u8 client_id,
170 struct ctrl_perf_volt_rail_list *prail_list)
171{
172 struct nv_pmu_volt_rpc rpc_call = { 0 };
173 struct obj_volt *pvolt = &g->perf_pmu.volt;
174 u32 status = 0;
175 u8 policy_idx = CTRL_VOLT_POLICY_INDEX_INVALID;
176 u8 i = 0;
177
178 /* Sanity check input rail list. */
179 for (i = 0; i < prail_list->num_rails; i++) {
180 if ((prail_list->rails[i].volt_domain ==
181 CTRL_VOLT_DOMAIN_INVALID) ||
182 (prail_list->rails[i].voltage_uv ==
183 NV_PMU_VOLT_VALUE_0V_IN_UV)) {
184 nvgpu_err(g, "Invalid voltage domain or target");
185 nvgpu_err(g, " client_id = %d, listEntry = %d",
186 client_id, i);
187 nvgpu_err(g, " volt_domain = %d, voltage_uv = %d uV.",
188 prail_list->rails[i].volt_domain,
189 prail_list->rails[i].voltage_uv);
190 status = -EINVAL;
191 goto exit;
192 }
193 }
194
195 /* Convert the client ID to index. */
196 if (client_id == CTRL_VOLT_POLICY_CLIENT_PERF_CORE_VF_SEQ)
197 policy_idx =
198 pvolt->volt_policy_metadata.perf_core_vf_seq_policy_idx;
199 else {
200 status = -EINVAL;
201 goto exit;
202 }
203
204 /* Set RPC parameters. */
205 rpc_call.function = NV_PMU_VOLT_RPC_ID_VOLT_POLICY_SET_VOLTAGE;
206 rpc_call.params.volt_policy_voltage_data.policy_idx = policy_idx;
207 memcpy(&rpc_call.params.volt_policy_voltage_data.rail_list, prail_list,
208 (sizeof(struct ctrl_perf_volt_rail_list)));
209
210 /* Execute the voltage change request via PMU RPC. */
211 status = volt_pmu_rpc_execute(g, &rpc_call);
212 if (status)
213 nvgpu_err(g,
214 "Error while executing VOLT_POLICY_SET_VOLTAGE RPC");
215
216exit:
217 return status;
218}
219
220u32 volt_set_voltage(struct gk20a *g, u32 logic_voltage_uv, u32 sram_voltage_uv)
221{
222 u32 status = 0;
223 struct ctrl_perf_volt_rail_list rail_list = { 0 };
224
225 rail_list.num_rails = RAIL_COUNT;
226 rail_list.rails[0].volt_domain = CTRL_VOLT_DOMAIN_LOGIC;
227 rail_list.rails[0].voltage_uv = logic_voltage_uv;
228 rail_list.rails[0].voltage_min_noise_unaware_uv = logic_voltage_uv;
229 rail_list.rails[1].volt_domain = CTRL_VOLT_DOMAIN_SRAM;
230 rail_list.rails[1].voltage_uv = sram_voltage_uv;
231 rail_list.rails[1].voltage_min_noise_unaware_uv = sram_voltage_uv;
232
233 status = volt_policy_set_voltage(g,
234 CTRL_VOLT_POLICY_CLIENT_PERF_CORE_VF_SEQ, &rail_list);
235
236 return status;
237
238}
239
240u32 volt_get_voltage(struct gk20a *g, u32 volt_domain, u32 *voltage_uv)
241{
242 return volt_rail_get_voltage(g, volt_domain, voltage_uv);
243}
244
245static int volt_policy_set_noiseaware_vmin(struct gk20a *g,
246 struct ctrl_volt_volt_rail_list *prail_list)
247{
248 struct nv_pmu_volt_rpc rpc_call = { 0 };
249 u32 status = 0;
250
251 /* Set RPC parameters. */
252 rpc_call.function = NV_PMU_VOLT_RPC_ID_VOLT_RAIL_SET_NOISE_UNAWARE_VMIN;
253 rpc_call.params.volt_rail_set_noise_unaware_vmin.num_rails =
254 prail_list->num_rails;
255 memcpy(&rpc_call.params.volt_rail_set_noise_unaware_vmin.rail_list,
256 prail_list, (sizeof(struct ctrl_volt_volt_rail_list)));
257
258 /* Execute the voltage change request via PMU RPC. */
259 status = volt_pmu_rpc_execute(g, &rpc_call);
260 if (status) {
261 nvgpu_err(g,
262 "Error while executing VOLT_POLICY_SET_VOLTAGE RPC");
263 return -EINVAL;
264 }
265
266 return 0;
267}
268
269int volt_set_noiseaware_vmin(struct gk20a *g, u32 logic_voltage_uv,
270 u32 sram_voltage_uv)
271{
272 int status = 0;
273 struct ctrl_volt_volt_rail_list rail_list = { 0 };
274
275 rail_list.num_rails = RAIL_COUNT;
276 rail_list.rails[0].rail_idx = 0;
277 rail_list.rails[0].voltage_uv = logic_voltage_uv;
278 rail_list.rails[1].rail_idx = 1;
279 rail_list.rails[1].voltage_uv = sram_voltage_uv;
280
281 status = volt_policy_set_noiseaware_vmin(g, &rail_list);
282
283 return status;
284
285}
286
diff --git a/drivers/gpu/nvgpu/volt/volt_pmu.h b/drivers/gpu/nvgpu/volt/volt_pmu.h
new file mode 100644
index 00000000..55be9c45
--- /dev/null
+++ b/drivers/gpu/nvgpu/volt/volt_pmu.h
@@ -0,0 +1,32 @@
1/*
2* Copyright (c) 2016, 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#ifndef _VOLT_PMU_H_
24#define _VOLT_PMU_H_
25
26u32 volt_pmu_send_load_cmd_to_pmu(struct gk20a *g);
27u32 volt_set_voltage(struct gk20a *g, u32 logic_voltage_uv,
28 u32 sram_voltage_uv);
29u32 volt_get_voltage(struct gk20a *g, u32 volt_domain, u32 *voltage_uv);
30int volt_set_noiseaware_vmin(struct gk20a *g, u32 logic_voltage_uv,
31 u32 sram_voltage_uv);
32#endif
diff --git a/drivers/gpu/nvgpu/volt/volt_policy.c b/drivers/gpu/nvgpu/volt/volt_policy.c
new file mode 100644
index 00000000..1e34b54f
--- /dev/null
+++ b/drivers/gpu/nvgpu/volt/volt_policy.c
@@ -0,0 +1,361 @@
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
33static u32 volt_policy_pmu_data_init_super(struct gk20a *g,
34 struct boardobj *pboardobj, struct nv_pmu_boardobj *ppmudata)
35{
36 return boardobj_pmudatainit_super(g, pboardobj, ppmudata);
37}
38
39static u32 construct_volt_policy(struct gk20a *g,
40 struct boardobj **ppboardobj, u16 size, void *pArgs)
41{
42 struct voltage_policy *pvolt_policy = NULL;
43 u32 status = 0;
44
45 status = boardobj_construct_super(g, ppboardobj, size, pArgs);
46 if (status)
47 return status;
48
49 pvolt_policy = (struct voltage_policy *)*ppboardobj;
50
51 pvolt_policy->super.pmudatainit = volt_policy_pmu_data_init_super;
52
53 return status;
54}
55
56static u32 construct_volt_policy_split_rail(struct gk20a *g,
57 struct boardobj **ppboardobj, u16 size, void *pArgs)
58{
59 struct voltage_policy_split_rail *ptmp_policy =
60 (struct voltage_policy_split_rail *)pArgs;
61 struct voltage_policy_split_rail *pvolt_policy = NULL;
62 u32 status = 0;
63
64 status = construct_volt_policy(g, ppboardobj, size, pArgs);
65 if (status)
66 return status;
67
68 pvolt_policy = (struct voltage_policy_split_rail *)*ppboardobj;
69
70 pvolt_policy->rail_idx_master = ptmp_policy->rail_idx_master;
71 pvolt_policy->rail_idx_slave = ptmp_policy->rail_idx_slave;
72 pvolt_policy->delta_min_vfe_equ_idx =
73 ptmp_policy->delta_min_vfe_equ_idx;
74 pvolt_policy->delta_max_vfe_equ_idx =
75 ptmp_policy->delta_max_vfe_equ_idx;
76
77 return status;
78}
79
80static u32 volt_policy_pmu_data_init_split_rail(struct gk20a *g,
81 struct boardobj *pboardobj, struct nv_pmu_boardobj *ppmudata)
82{
83 u32 status = 0;
84 struct voltage_policy_split_rail *ppolicy;
85 struct nv_pmu_volt_volt_policy_splt_r_boardobj_set *pset;
86
87 status = volt_policy_pmu_data_init_super(g, pboardobj, ppmudata);
88 if (status)
89 goto done;
90
91 ppolicy = (struct voltage_policy_split_rail *)pboardobj;
92 pset = (struct nv_pmu_volt_volt_policy_splt_r_boardobj_set *)
93 ppmudata;
94
95 pset->rail_idx_master = ppolicy->rail_idx_master;
96 pset->rail_idx_slave = ppolicy->rail_idx_slave;
97 pset->delta_min_vfe_equ_idx = ppolicy->delta_min_vfe_equ_idx;
98 pset->delta_max_vfe_equ_idx = ppolicy->delta_max_vfe_equ_idx;
99 pset->offset_delta_min_uv = ppolicy->offset_delta_min_uv;
100 pset->offset_delta_max_uv = ppolicy->offset_delta_max_uv;
101
102done:
103 return status;
104}
105
106static u32 volt_construct_volt_policy_split_rail_single_step(struct gk20a *g,
107 struct boardobj **ppboardobj, u16 size, void *pargs)
108{
109 struct boardobj *pboardobj = NULL;
110 struct voltage_policy_split_rail_single_step *p_volt_policy = NULL;
111 u32 status = 0;
112
113 status = construct_volt_policy_split_rail(g, ppboardobj, size, pargs);
114 if (status)
115 return status;
116
117 pboardobj = (*ppboardobj);
118 p_volt_policy = (struct voltage_policy_split_rail_single_step *)
119 *ppboardobj;
120
121 pboardobj->pmudatainit = volt_policy_pmu_data_init_split_rail;
122
123 return status;
124}
125
126static struct voltage_policy *volt_volt_policy_construct(struct gk20a *g, void *pargs)
127{
128 struct boardobj *pboard_obj = NULL;
129 u32 status = 0;
130
131 if (BOARDOBJ_GET_TYPE(pargs) ==
132 CTRL_VOLT_POLICY_TYPE_SR_SINGLE_STEP) {
133 status = volt_construct_volt_policy_split_rail_single_step(g,
134 &pboard_obj,
135 sizeof(struct voltage_policy_split_rail_single_step),
136 pargs);
137 if (status) {
138 nvgpu_err(g,
139 "Could not allocate memory for voltage_policy");
140 pboard_obj = NULL;
141 }
142 }
143
144 return (struct voltage_policy *)pboard_obj;
145}
146
147static u8 volt_policy_type_convert(u8 vbios_type)
148{
149 switch (vbios_type) {
150 case NV_VBIOS_VOLTAGE_POLICY_1X_ENTRY_TYPE_SINGLE_RAIL:
151 return CTRL_VOLT_POLICY_TYPE_SINGLE_RAIL;
152
153 case NV_VBIOS_VOLTAGE_POLICY_1X_ENTRY_TYPE_SR_MULTI_STEP:
154 return CTRL_VOLT_POLICY_TYPE_SR_MULTI_STEP;
155
156 case NV_VBIOS_VOLTAGE_POLICY_1X_ENTRY_TYPE_SR_SINGLE_STEP:
157 return CTRL_VOLT_POLICY_TYPE_SR_SINGLE_STEP;
158 }
159
160 return CTRL_VOLT_POLICY_TYPE_INVALID;
161}
162
163static u32 volt_get_volt_policy_table(struct gk20a *g,
164 struct voltage_policy_metadata *pvolt_policy_metadata)
165{
166 u32 status = 0;
167 u8 *voltage_policy_table_ptr = NULL;
168 struct voltage_policy *ppolicy = NULL;
169 struct vbios_voltage_policy_table_1x_header header = { 0 };
170 struct vbios_voltage_policy_table_1x_entry entry = { 0 };
171 u8 i;
172 u8 policy_type = 0;
173 u8 *entry_offset;
174 union policy_type {
175 struct boardobj board_obj;
176 struct voltage_policy volt_policy;
177 struct voltage_policy_split_rail split_rail;
178 } policy_type_data;
179
180 voltage_policy_table_ptr =
181 (u8 *)nvgpu_bios_get_perf_table_ptrs(g,
182 g->bios.perf_token, VOLTAGE_POLICY_TABLE);
183 if (voltage_policy_table_ptr == NULL) {
184 status = -EINVAL;
185 goto done;
186 }
187
188 memcpy(&header, voltage_policy_table_ptr,
189 sizeof(struct vbios_voltage_policy_table_1x_header));
190
191 /* Set Voltage Policy Table Index for Perf Core VF Sequence client. */
192 pvolt_policy_metadata->perf_core_vf_seq_policy_idx =
193 (u8)header.perf_core_vf_seq_policy_idx;
194
195 /* Read in the entries. */
196 for (i = 0; i < header.num_table_entries; i++) {
197 entry_offset = (voltage_policy_table_ptr + header.header_size +
198 i * header.table_entry_size);
199
200 memcpy(&entry, entry_offset,
201 sizeof(struct vbios_voltage_policy_table_1x_entry));
202
203 memset(&policy_type_data, 0x0, sizeof(policy_type_data));
204
205 policy_type = volt_policy_type_convert((u8)entry.type);
206
207 if (policy_type == CTRL_VOLT_POLICY_TYPE_SR_SINGLE_STEP) {
208 policy_type_data.split_rail.rail_idx_master =
209 (u8)BIOS_GET_FIELD(entry.param0,
210 NV_VBIOS_VPT_ENTRY_PARAM0_SR_VD_MASTER);
211
212 policy_type_data.split_rail.rail_idx_slave =
213 (u8)BIOS_GET_FIELD(entry.param0,
214 NV_VBIOS_VPT_ENTRY_PARAM0_SR_VD_SLAVE);
215
216 policy_type_data.split_rail.delta_min_vfe_equ_idx =
217 (u8)BIOS_GET_FIELD(entry.param0,
218 NV_VBIOS_VPT_ENTRY_PARAM0_SR_DELTA_SM_MIN);
219
220 policy_type_data.split_rail.delta_max_vfe_equ_idx =
221 (u8)BIOS_GET_FIELD(entry.param0,
222 NV_VBIOS_VPT_ENTRY_PARAM0_SR_DELTA_SM_MAX);
223 }
224
225 policy_type_data.board_obj.type = policy_type;
226
227 ppolicy = volt_volt_policy_construct(g,
228 (void *)&policy_type_data);
229 if (ppolicy == NULL) {
230 nvgpu_err(g,
231 "Failure to construct VOLT_POLICY object.");
232 status = -EINVAL;
233 goto done;
234 }
235
236 status = boardobjgrp_objinsert(
237 &pvolt_policy_metadata->volt_policies.super,
238 (struct boardobj *)ppolicy, i);
239 if (status) {
240 nvgpu_err(g,
241 "could not add volt_policy for entry %d into boardobjgrp ",
242 i);
243 goto done;
244 }
245 }
246
247done:
248 return status;
249}
250static u32 _volt_policy_devgrp_pmudata_instget(struct gk20a *g,
251 struct nv_pmu_boardobjgrp *pmuboardobjgrp,
252 struct nv_pmu_boardobj **ppboardobjpmudata, u8 idx)
253{
254 struct nv_pmu_volt_volt_policy_boardobj_grp_set *pgrp_set =
255 (struct nv_pmu_volt_volt_policy_boardobj_grp_set *)
256 pmuboardobjgrp;
257
258 gk20a_dbg_info("");
259
260 /*check whether pmuboardobjgrp has a valid boardobj in index*/
261 if (((u32)BIT(idx) &
262 pgrp_set->hdr.data.super.obj_mask.super.data[0]) == 0)
263 return -EINVAL;
264
265 *ppboardobjpmudata = (struct nv_pmu_boardobj *)
266 &pgrp_set->objects[idx].data.board_obj;
267 gk20a_dbg_info(" Done");
268 return 0;
269}
270
271static u32 _volt_policy_devgrp_pmustatus_instget(struct gk20a *g,
272 void *pboardobjgrppmu,
273 struct nv_pmu_boardobj_query **ppboardobjpmustatus, u8 idx)
274{
275 struct nv_pmu_volt_volt_policy_boardobj_grp_get_status *p_get_status =
276 (struct nv_pmu_volt_volt_policy_boardobj_grp_get_status *)
277 pboardobjgrppmu;
278
279 /*check whether pmuboardobjgrp has a valid boardobj in index*/
280 if (((u32)BIT(idx) &
281 p_get_status->hdr.data.super.obj_mask.super.data[0]) == 0)
282 return -EINVAL;
283
284 *ppboardobjpmustatus = (struct nv_pmu_boardobj_query *)
285 &p_get_status->objects[idx].data.board_obj;
286 return 0;
287}
288
289u32 volt_policy_pmu_setup(struct gk20a *g)
290{
291 u32 status;
292 struct boardobjgrp *pboardobjgrp = NULL;
293
294 gk20a_dbg_info("");
295
296 pboardobjgrp =
297 &g->perf_pmu.volt.volt_policy_metadata.volt_policies.super;
298
299 if (!pboardobjgrp->bconstructed)
300 return -EINVAL;
301
302 status = pboardobjgrp->pmuinithandle(g, pboardobjgrp);
303
304 gk20a_dbg_info("Done");
305 return status;
306}
307
308u32 volt_policy_sw_setup(struct gk20a *g)
309{
310 u32 status = 0;
311 struct boardobjgrp *pboardobjgrp = NULL;
312
313 gk20a_dbg_info("");
314
315 status = boardobjgrpconstruct_e32(g,
316 &g->perf_pmu.volt.volt_policy_metadata.volt_policies);
317 if (status) {
318 nvgpu_err(g,
319 "error creating boardobjgrp for volt rail, status - 0x%x",
320 status);
321 goto done;
322 }
323
324 pboardobjgrp =
325 &g->perf_pmu.volt.volt_policy_metadata.volt_policies.super;
326
327 pboardobjgrp->pmudatainstget = _volt_policy_devgrp_pmudata_instget;
328 pboardobjgrp->pmustatusinstget = _volt_policy_devgrp_pmustatus_instget;
329
330 /* Obtain Voltage Rail Table from VBIOS */
331 status = volt_get_volt_policy_table(g, &g->perf_pmu.volt.
332 volt_policy_metadata);
333 if (status)
334 goto done;
335
336 /* Populate data for the VOLT_RAIL PMU interface */
337 BOARDOBJGRP_PMU_CONSTRUCT(pboardobjgrp, VOLT, VOLT_POLICY);
338
339 status = BOARDOBJGRP_PMU_CMD_GRP_SET_CONSTRUCT(g, pboardobjgrp,
340 volt, VOLT, volt_policy, VOLT_POLICY);
341 if (status) {
342 nvgpu_err(g,
343 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
344 status);
345 goto done;
346 }
347
348 status = BOARDOBJGRP_PMU_CMD_GRP_GET_STATUS_CONSTRUCT(g,
349 &g->perf_pmu.volt.volt_policy_metadata.volt_policies.super,
350 volt, VOLT, volt_policy, VOLT_POLICY);
351 if (status) {
352 nvgpu_err(g,
353 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
354 status);
355 goto done;
356 }
357
358done:
359 gk20a_dbg_info(" done status %x", status);
360 return status;
361}
diff --git a/drivers/gpu/nvgpu/volt/volt_policy.h b/drivers/gpu/nvgpu/volt/volt_policy.h
new file mode 100644
index 00000000..8db79218
--- /dev/null
+++ b/drivers/gpu/nvgpu/volt/volt_policy.h
@@ -0,0 +1,73 @@
1/*
2* Copyright (c) 2016, 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#ifndef _VOLT_POLICY_H_
24#define _VOLT_POLICY_H_
25
26#define VOLT_POLICY_INDEX_IS_VALID(pvolt, policy_idx) \
27 (boardobjgrp_idxisvalid( \
28 &((pvolt)->volt_policy_metadata.volt_policies.super), \
29 (policy_idx)))
30
31/*!
32 * extends boardobj providing attributes common to all voltage_policies.
33 */
34struct voltage_policy {
35 struct boardobj super;
36};
37
38struct voltage_policy_metadata {
39 u8 perf_core_vf_seq_policy_idx;
40 struct boardobjgrp_e32 volt_policies;
41};
42
43/*!
44 * extends voltage_policy providing attributes
45 * common to all voltage_policy_split_rail.
46 */
47struct voltage_policy_split_rail {
48 struct voltage_policy super;
49 u8 rail_idx_master;
50 u8 rail_idx_slave;
51 u8 delta_min_vfe_equ_idx;
52 u8 delta_max_vfe_equ_idx;
53 s32 offset_delta_min_uv;
54 s32 offset_delta_max_uv;
55};
56
57struct voltage_policy_split_rail_single_step {
58 struct voltage_policy_split_rail super;
59};
60
61struct voltage_policy_split_rail_multi_step {
62 struct voltage_policy_split_rail super;
63 u16 inter_switch_delay_us;
64};
65
66struct voltage_policy_single_rail {
67 struct voltage_policy super;
68 u8 rail_idx;
69};
70
71u32 volt_policy_sw_setup(struct gk20a *g);
72u32 volt_policy_pmu_setup(struct gk20a *g);
73#endif
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}
diff --git a/drivers/gpu/nvgpu/volt/volt_rail.h b/drivers/gpu/nvgpu/volt/volt_rail.h
new file mode 100644
index 00000000..9a3fcda0
--- /dev/null
+++ b/drivers/gpu/nvgpu/volt/volt_rail.h
@@ -0,0 +1,88 @@
1/*
2* Copyright (c) 2016, 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#ifndef _VOLT_RAIL_H_
25#define _VOLT_RAIL_H_
26
27#include "boardobj/boardobj.h"
28#include "boardobj/boardobjgrp.h"
29
30#define CTRL_VOLT_RAIL_VOLT_DELTA_MAX_ENTRIES 0x04
31#define CTRL_PMGR_PWR_EQUATION_INDEX_INVALID 0xFF
32
33#define VOLT_GET_VOLT_RAIL(pvolt, rail_idx) \
34 ((struct voltage_rail *)BOARDOBJGRP_OBJ_GET_BY_IDX( \
35 &((pvolt)->volt_rail_metadata.volt_rails.super), (rail_idx)))
36
37#define VOLT_RAIL_INDEX_IS_VALID(pvolt, rail_idx) \
38 (boardobjgrp_idxisvalid( \
39 &((pvolt)->volt_rail_metadata.volt_rails.super), (rail_idx)))
40
41#define VOLT_RAIL_VOLT_3X_SUPPORTED(pvolt) \
42 (!BOARDOBJGRP_IS_EMPTY(&((pvolt)->volt_rail_metadata.volt_rails.super)))
43
44/*!
45 * extends boardobj providing attributes common to all voltage_rails.
46 */
47struct voltage_rail {
48 struct boardobj super;
49 u32 boot_voltage_uv;
50 u8 rel_limit_vfe_equ_idx;
51 u8 alt_rel_limit_vfe_equ_idx;
52 u8 ov_limit_vfe_equ_idx;
53 u8 pwr_equ_idx;
54 u8 volt_dev_idx_default;
55 u8 boot_volt_vfe_equ_idx;
56 u8 vmin_limit_vfe_equ_idx;
57 u8 volt_margin_limit_vfe_equ_idx;
58 u32 volt_margin_limit_vfe_equ_mon_handle;
59 u32 rel_limit_vfe_equ_mon_handle;
60 u32 alt_rel_limit_vfe_equ_mon_handle;
61 u32 ov_limit_vfe_equ_mon_handle;
62 struct boardobjgrpmask_e32 volt_dev_mask;
63 s32 volt_delta_uv[CTRL_VOLT_RAIL_VOLT_DELTA_MAX_ENTRIES];
64};
65
66/*!
67 * metadata of voltage rail functionality.
68 */
69struct voltage_rail_metadata {
70 u8 volt_domain_hal;
71 u8 pct_delta;
72 u32 ext_rel_delta_uv[CTRL_VOLT_RAIL_VOLT_DELTA_MAX_ENTRIES];
73 u8 logic_rail_idx;
74 u8 sram_rail_idx;
75 struct boardobjgrp_e32 volt_rails;
76};
77
78u8 volt_rail_vbios_volt_domain_convert_to_internal
79 (struct gk20a *g, u8 vbios_volt_domain);
80
81u32 volt_rail_volt_dev_register(struct gk20a *g, struct voltage_rail
82 *pvolt_rail, u8 volt_dev_idx, u8 operation_type);
83
84u8 volt_rail_volt_domain_convert_to_idx(struct gk20a *g, u8 volt_domain);
85
86u32 volt_rail_sw_setup(struct gk20a *g);
87u32 volt_rail_pmu_setup(struct gk20a *g);
88#endif