diff options
author | Mahantesh Kumbar <mkumbar@nvidia.com> | 2016-09-19 01:37:46 -0400 |
---|---|---|
committer | Deepak Nibade <dnibade@nvidia.com> | 2016-12-27 04:56:50 -0500 |
commit | 173bdefc92e2e4ef8f1e7e6ead7f86e746bee935 (patch) | |
tree | 69d9a43a453e988c54927ade2f5ce04457eaf312 /drivers/gpu/nvgpu/volt/volt_policy.c | |
parent | db529935a5f50e9e683d44d2eb01d0d76a915792 (diff) |
gpu: nvgpu: add support for voltage config
- changes to read voltage tables from VBIOS
& create boardobj then send to pmu
- Rail, Device & Policy objects are read from VBIOS & created boardobjs
- RPC support to load, Set & get voltage.
JIRA DNVGPU-122
Change-Id: I61621a514eef9c081a64c4ab066f01dfc28f8402
Signed-off-by: Mahantesh Kumbar <mkumbar@nvidia.com>
Reviewed-on: http://git-master/r/1222774
(cherry picked from commit 9da86d8c2c547623cf5f38c89afeb3f5bb1667ac)
Reviewed-on: http://git-master/r/1244656
GVS: Gerrit_Virtual_Submit
Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com>
Tested-by: Terje Bergstrom <tbergstrom@nvidia.com>
Diffstat (limited to 'drivers/gpu/nvgpu/volt/volt_policy.c')
-rw-r--r-- | drivers/gpu/nvgpu/volt/volt_policy.c | 360 |
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 | |||
27 | static 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 | |||
33 | static 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 | |||
50 | static 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 | |||
74 | u32 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 | |||
96 | done: | ||
97 | return status; | ||
98 | } | ||
99 | |||
100 | static 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 | |||
120 | struct 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 | |||
141 | static 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 | |||
157 | static 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 | |||
246 | done: | ||
247 | return status; | ||
248 | } | ||
249 | static 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 | |||
270 | static 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 | |||
288 | u32 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 | |||
307 | u32 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 | |||
357 | done: | ||
358 | gk20a_dbg_info(" done status %x", status); | ||
359 | return status; | ||
360 | } | ||