summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/volt/volt_policy.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/nvgpu/volt/volt_policy.c')
-rw-r--r--drivers/gpu/nvgpu/volt/volt_policy.c360
1 files changed, 360 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/volt/volt_policy.c b/drivers/gpu/nvgpu/volt/volt_policy.c
new file mode 100644
index 00000000..ee3e74b8
--- /dev/null
+++ b/drivers/gpu/nvgpu/volt/volt_policy.c
@@ -0,0 +1,360 @@
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
27static u32 volt_policy_pmu_data_init_super(struct gk20a *g,
28 struct boardobj *pboardobj, struct nv_pmu_boardobj *ppmudata)
29{
30 return boardobj_pmudatainit_super(g, pboardobj, ppmudata);
31}
32
33static u32 construct_volt_policy(struct gk20a *g,
34 struct boardobj **ppboardobj, u16 size, void *pArgs)
35{
36 struct voltage_policy *pvolt_policy = NULL;
37 u32 status = 0;
38
39 status = boardobj_construct_super(g, ppboardobj, size, pArgs);
40 if (status)
41 return status;
42
43 pvolt_policy = (struct voltage_policy *)*ppboardobj;
44
45 pvolt_policy->super.pmudatainit = volt_policy_pmu_data_init_super;
46
47 return status;
48}
49
50static u32 construct_volt_policy_split_rail(struct gk20a *g,
51 struct boardobj **ppboardobj, u16 size, void *pArgs)
52{
53 struct voltage_policy_split_rail *ptmp_policy =
54 (struct voltage_policy_split_rail *)pArgs;
55 struct voltage_policy_split_rail *pvolt_policy = NULL;
56 u32 status = 0;
57
58 status = construct_volt_policy(g, ppboardobj, size, pArgs);
59 if (status)
60 return status;
61
62 pvolt_policy = (struct voltage_policy_split_rail *)*ppboardobj;
63
64 pvolt_policy->rail_idx_master = ptmp_policy->rail_idx_master;
65 pvolt_policy->rail_idx_slave = ptmp_policy->rail_idx_slave;
66 pvolt_policy->delta_min_vfe_equ_idx =
67 ptmp_policy->delta_min_vfe_equ_idx;
68 pvolt_policy->delta_max_vfe_equ_idx =
69 ptmp_policy->delta_max_vfe_equ_idx;
70
71 return status;
72}
73
74u32 volt_policy_pmu_data_init_split_rail(struct gk20a *g,
75 struct boardobj *pboardobj, struct nv_pmu_boardobj *ppmudata)
76{
77 u32 status = 0;
78 struct voltage_policy_split_rail *ppolicy;
79 struct nv_pmu_volt_volt_policy_splt_r_boardobj_set *pset;
80
81 status = volt_policy_pmu_data_init_super(g, pboardobj, ppmudata);
82 if (status)
83 goto done;
84
85 ppolicy = (struct voltage_policy_split_rail *)pboardobj;
86 pset = (struct nv_pmu_volt_volt_policy_splt_r_boardobj_set *)
87 ppmudata;
88
89 pset->rail_idx_master = ppolicy->rail_idx_master;
90 pset->rail_idx_slave = ppolicy->rail_idx_slave;
91 pset->delta_min_vfe_equ_idx = ppolicy->delta_min_vfe_equ_idx;
92 pset->delta_max_vfe_equ_idx = ppolicy->delta_max_vfe_equ_idx;
93 pset->offset_delta_min_uv = ppolicy->offset_delta_min_uv;
94 pset->offset_delta_max_uv = ppolicy->offset_delta_max_uv;
95
96done:
97 return status;
98}
99
100static u32 volt_construct_volt_policy_split_rail_single_step(struct gk20a *g,
101 struct boardobj **ppboardobj, u16 size, void *pargs)
102{
103 struct boardobj *pboardobj = NULL;
104 struct voltage_policy_split_rail_single_step *p_volt_policy = NULL;
105 u32 status = 0;
106
107 status = construct_volt_policy_split_rail(g, ppboardobj, size, pargs);
108 if (status)
109 return status;
110
111 pboardobj = (*ppboardobj);
112 p_volt_policy = (struct voltage_policy_split_rail_single_step *)
113 *ppboardobj;
114
115 pboardobj->pmudatainit = volt_policy_pmu_data_init_split_rail;
116
117 return status;
118}
119
120struct voltage_policy *volt_volt_policy_construct(struct gk20a *g, void *pargs)
121{
122 struct boardobj *pboard_obj = NULL;
123 u32 status = 0;
124
125 if (BOARDOBJ_GET_TYPE(pargs) ==
126 CTRL_VOLT_POLICY_TYPE_SR_SINGLE_STEP) {
127 status = volt_construct_volt_policy_split_rail_single_step(g,
128 &pboard_obj,
129 sizeof(struct voltage_policy_split_rail_single_step),
130 pargs);
131 if (status) {
132 gk20a_err(dev_from_gk20a(g),
133 "Could not allocate memory for voltage_policy");
134 pboard_obj = NULL;
135 }
136 }
137
138 return (struct voltage_policy *)pboard_obj;
139}
140
141static u8 volt_policy_type_convert(u8 vbios_type)
142{
143 switch (vbios_type) {
144 case NV_VBIOS_VOLTAGE_POLICY_1X_ENTRY_TYPE_SINGLE_RAIL:
145 return CTRL_VOLT_POLICY_TYPE_SINGLE_RAIL;
146
147 case NV_VBIOS_VOLTAGE_POLICY_1X_ENTRY_TYPE_SR_MULTI_STEP:
148 return CTRL_VOLT_POLICY_TYPE_SR_MULTI_STEP;
149
150 case NV_VBIOS_VOLTAGE_POLICY_1X_ENTRY_TYPE_SR_SINGLE_STEP:
151 return CTRL_VOLT_POLICY_TYPE_SR_SINGLE_STEP;
152 }
153
154 return CTRL_VOLT_POLICY_TYPE_INVALID;
155}
156
157static u32 volt_get_volt_policy_table(struct gk20a *g,
158 struct voltage_policy_metadata *pvolt_policy_metadata)
159{
160 u32 status = 0;
161 u8 *voltage_policy_table_ptr = NULL;
162 struct voltage_policy *ppolicy = NULL;
163 struct vbios_voltage_policy_table_1x_header header = { 0 };
164 struct vbios_voltage_policy_table_1x_entry entry = { 0 };
165 u8 i;
166 u8 policy_type = 0;
167 u8 *entry_offset;
168 union policy_type {
169 struct boardobj board_obj;
170 struct voltage_policy volt_policy;
171 struct voltage_policy_split_rail split_rail;
172 } policy_type_data;
173
174 if (g->ops.bios.get_perf_table_ptrs) {
175 voltage_policy_table_ptr =
176 (u8 *)g->ops.bios.get_perf_table_ptrs(g,
177 g->bios.perf_token, VOLTAGE_POLICY_TABLE);
178 if (voltage_policy_table_ptr == NULL) {
179 status = -EINVAL;
180 goto done;
181 }
182 } else {
183 status = -EINVAL;
184 goto done;
185 }
186
187 memcpy(&header, voltage_policy_table_ptr,
188 sizeof(struct vbios_voltage_policy_table_1x_header));
189
190 /* Set Voltage Policy Table Index for Perf Core VF Sequence client. */
191 pvolt_policy_metadata->perf_core_vf_seq_policy_idx =
192 (u8)header.perf_core_vf_seq_policy_idx;
193
194 /* Read in the entries. */
195 for (i = 0; i < header.num_table_entries; i++) {
196 entry_offset = (voltage_policy_table_ptr + header.header_size +
197 i * header.table_entry_size);
198
199 memcpy(&entry, entry_offset,
200 sizeof(struct vbios_voltage_policy_table_1x_entry));
201
202 memset(&policy_type_data, 0x0, sizeof(policy_type_data));
203
204 policy_type = volt_policy_type_convert((u8)entry.type);
205
206 if (policy_type == CTRL_VOLT_POLICY_TYPE_SR_SINGLE_STEP) {
207 policy_type_data.split_rail.rail_idx_master =
208 (u8)BIOS_GET_FIELD(entry.param0,
209 NV_VBIOS_VPT_ENTRY_PARAM0_SR_VD_MASTER);
210
211 policy_type_data.split_rail.rail_idx_slave =
212 (u8)BIOS_GET_FIELD(entry.param0,
213 NV_VBIOS_VPT_ENTRY_PARAM0_SR_VD_SLAVE);
214
215 policy_type_data.split_rail.delta_min_vfe_equ_idx =
216 (u8)BIOS_GET_FIELD(entry.param0,
217 NV_VBIOS_VPT_ENTRY_PARAM0_SR_DELTA_SM_MIN);
218
219 policy_type_data.split_rail.delta_max_vfe_equ_idx =
220 (u8)BIOS_GET_FIELD(entry.param0,
221 NV_VBIOS_VPT_ENTRY_PARAM0_SR_DELTA_SM_MAX);
222 }
223
224 policy_type_data.board_obj.type = policy_type;
225
226 ppolicy = volt_volt_policy_construct(g,
227 (void *)&policy_type_data);
228 if (ppolicy == NULL) {
229 gk20a_err(dev_from_gk20a(g),
230 "Failure to construct VOLT_POLICY object.");
231 status = -EINVAL;
232 goto done;
233 }
234
235 status = boardobjgrp_objinsert(
236 &pvolt_policy_metadata->volt_policies.super,
237 (struct boardobj *)ppolicy, i);
238 if (status) {
239 gk20a_err(dev_from_gk20a(g),
240 "could not add volt_policy for entry %d into boardobjgrp ",
241 i);
242 goto done;
243 }
244 }
245
246done:
247 return status;
248}
249static u32 _volt_policy_devgrp_pmudata_instget(struct gk20a *g,
250 struct nv_pmu_boardobjgrp *pmuboardobjgrp,
251 struct nv_pmu_boardobj **ppboardobjpmudata, u8 idx)
252{
253 struct nv_pmu_volt_volt_policy_boardobj_grp_set *pgrp_set =
254 (struct nv_pmu_volt_volt_policy_boardobj_grp_set *)
255 pmuboardobjgrp;
256
257 gk20a_dbg_info("");
258
259 /*check whether pmuboardobjgrp has a valid boardobj in index*/
260 if (((u32)BIT(idx) &
261 pgrp_set->hdr.data.super.obj_mask.super.data[0]) == 0)
262 return -EINVAL;
263
264 *ppboardobjpmudata = (struct nv_pmu_boardobj *)
265 &pgrp_set->objects[idx].data.board_obj;
266 gk20a_dbg_info(" Done");
267 return 0;
268}
269
270static u32 _volt_policy_devgrp_pmustatus_instget(struct gk20a *g,
271 void *pboardobjgrppmu,
272 struct nv_pmu_boardobj_query **ppboardobjpmustatus, u8 idx)
273{
274 struct nv_pmu_volt_volt_policy_boardobj_grp_get_status *p_get_status =
275 (struct nv_pmu_volt_volt_policy_boardobj_grp_get_status *)
276 pboardobjgrppmu;
277
278 /*check whether pmuboardobjgrp has a valid boardobj in index*/
279 if (((u32)BIT(idx) &
280 p_get_status->hdr.data.super.obj_mask.super.data[0]) == 0)
281 return -EINVAL;
282
283 *ppboardobjpmustatus = (struct nv_pmu_boardobj_query *)
284 &p_get_status->objects[idx].data.board_obj;
285 return 0;
286}
287
288u32 volt_policy_pmu_setup(struct gk20a *g)
289{
290 u32 status;
291 struct boardobjgrp *pboardobjgrp = NULL;
292
293 gk20a_dbg_info("");
294
295 pboardobjgrp =
296 &g->perf_pmu.volt.volt_policy_metadata.volt_policies.super;
297
298 if (!pboardobjgrp->bconstructed)
299 return -EINVAL;
300
301 status = pboardobjgrp->pmuinithandle(g, pboardobjgrp);
302
303 gk20a_dbg_info("Done");
304 return status;
305}
306
307u32 volt_policy_sw_setup(struct gk20a *g)
308{
309 u32 status = 0;
310 struct boardobjgrp *pboardobjgrp = NULL;
311
312 gk20a_dbg_info("");
313
314 status = boardobjgrpconstruct_e32(
315 &g->perf_pmu.volt.volt_policy_metadata.volt_policies);
316 if (status) {
317 gk20a_err(dev_from_gk20a(g),
318 "error creating boardobjgrp for volt rail, status - 0x%x",
319 status);
320 goto done;
321 }
322
323 pboardobjgrp =
324 &g->perf_pmu.volt.volt_policy_metadata.volt_policies.super;
325
326 pboardobjgrp->pmudatainstget = _volt_policy_devgrp_pmudata_instget;
327 pboardobjgrp->pmustatusinstget = _volt_policy_devgrp_pmustatus_instget;
328
329 /* Obtain Voltage Rail Table from VBIOS */
330 status = volt_get_volt_policy_table(g, &g->perf_pmu.volt.
331 volt_policy_metadata);
332 if (status)
333 goto done;
334
335 /* Populate data for the VOLT_RAIL PMU interface */
336 BOARDOBJGRP_PMU_CONSTRUCT(pboardobjgrp, VOLT, VOLT_POLICY);
337
338 status = BOARDOBJGRP_PMU_CMD_GRP_SET_CONSTRUCT(g, pboardobjgrp,
339 volt, VOLT, volt_policy, VOLT_POLICY);
340 if (status) {
341 gk20a_err(dev_from_gk20a(g),
342 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
343 status);
344 goto done;
345 }
346
347 status = BOARDOBJGRP_PMU_CMD_GRP_GET_STATUS_CONSTRUCT(g,
348 &g->perf_pmu.volt.volt_policy_metadata.volt_policies.super,
349 volt, VOLT, volt_policy, VOLT_POLICY);
350 if (status) {
351 gk20a_err(dev_from_gk20a(g),
352 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
353 status);
354 goto done;
355 }
356
357done:
358 gk20a_dbg_info(" done status %x", status);
359 return status;
360}