summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/pmgr/pwrdev.c
diff options
context:
space:
mode:
authorLakshmanan M <lm@nvidia.com>2016-09-08 13:28:19 -0400
committerDeepak Nibade <dnibade@nvidia.com>2016-12-27 04:56:50 -0500
commit90f80a282eff04412858361df35c2f88372e88cb (patch)
tree4de1169e9bc3f02416a01c933175b613f9ccbdfd /drivers/gpu/nvgpu/pmgr/pwrdev.c
parentcb78f5aa749fcea198851ae4adf6e3acd47b37ac (diff)
gpu: nvgpu: Add pmgr support
This CL covers the following implementation, 1) Power Sensor Table parsing. 2) Power Topology Table parsing. 3) Add debugfs interface to get the current power(mW), current(mA) and voltage(uV) information from PMU. 4) Power Policy Table Parsing 5) Implement PMU boardobj interface for pmgr module. 6) Over current protection. JIRA DNVGPU-47 Change-Id: I7b1eefacc4f0a9824ab94ec8dcebefe81b7660d3 Signed-off-by: Lakshmanan M <lm@nvidia.com> Reviewed-on: http://git-master/r/1217189 (cherry picked from commit ecd0b16316cb4110118c6677f5f03e02921c29b6) Reviewed-on: http://git-master/r/1241953 Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com> GVS: Gerrit_Virtual_Submit
Diffstat (limited to 'drivers/gpu/nvgpu/pmgr/pwrdev.c')
-rw-r--r--drivers/gpu/nvgpu/pmgr/pwrdev.c310
1 files changed, 310 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/pmgr/pwrdev.c b/drivers/gpu/nvgpu/pmgr/pwrdev.c
new file mode 100644
index 00000000..03e2eb34
--- /dev/null
+++ b/drivers/gpu/nvgpu/pmgr/pwrdev.c
@@ -0,0 +1,310 @@
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 "pwrdev.h"
16#include "include/bios.h"
17#include "boardobj/boardobjgrp.h"
18#include "boardobj/boardobjgrp_e32.h"
19#include "pmuif/gpmuifboardobj.h"
20#include "pmuif/gpmuifpmgr.h"
21#include "gm206/bios_gm206.h"
22#include "gk20a/pmu_gk20a.h"
23
24static u32 _pwr_device_pmudata_instget(struct gk20a *g,
25 struct nv_pmu_boardobjgrp *pmuboardobjgrp,
26 struct nv_pmu_boardobj **ppboardobjpmudata,
27 u8 idx)
28{
29 struct nv_pmu_pmgr_pwr_device_desc_table *ppmgrdevice =
30 (struct nv_pmu_pmgr_pwr_device_desc_table *)pmuboardobjgrp;
31
32 gk20a_dbg_info("");
33
34 /*check whether pmuboardobjgrp has a valid boardobj in index*/
35 if (((u32)BIT(idx) &
36 ppmgrdevice->hdr.data.super.obj_mask.super.data[0]) == 0)
37 return -EINVAL;
38
39 *ppboardobjpmudata = (struct nv_pmu_boardobj *)
40 &ppmgrdevice->devices[idx].data.board_obj;
41
42 gk20a_dbg_info(" Done");
43
44 return 0;
45}
46
47static u32 _pwr_domains_pmudatainit_ina3221(struct gk20a *g,
48 struct boardobj *board_obj_ptr,
49 struct nv_pmu_boardobj *ppmudata)
50{
51 struct nv_pmu_pmgr_pwr_device_desc_ina3221 *ina3221_desc;
52 struct pwr_device_ina3221 *ina3221;
53 u32 status = 0;
54 u32 indx;
55
56 status = boardobj_pmudatainit_super(g, board_obj_ptr, ppmudata);
57 if (status) {
58 gk20a_err(dev_from_gk20a(g),
59 "error updating pmu boardobjgrp for pwr domain 0x%x",
60 status);
61 goto done;
62 }
63
64 ina3221 = (struct pwr_device_ina3221 *)board_obj_ptr;
65 ina3221_desc = (struct nv_pmu_pmgr_pwr_device_desc_ina3221 *) ppmudata;
66
67 ina3221_desc->super.power_corr_factor = ina3221->super.power_corr_factor;
68 ina3221_desc->i2c_dev_idx = ina3221->super.i2c_dev_idx;
69 ina3221_desc->configuration = ina3221->configuration;
70 ina3221_desc->mask_enable = ina3221->mask_enable;
71 /* configure NV_PMU_THERM_EVENT_EXT_OVERT */
72 ina3221_desc->event_mask = (1 << 0);
73 ina3221_desc->curr_correct_m = ina3221->curr_correct_m;
74 ina3221_desc->curr_correct_b = ina3221->curr_correct_b;
75
76 for (indx = 0; indx < NV_PMU_PMGR_PWR_DEVICE_INA3221_CH_NUM; indx++) {
77 ina3221_desc->r_shuntm_ohm[indx] = ina3221->r_shuntm_ohm[indx];
78 }
79
80done:
81 return status;
82}
83
84static struct boardobj *construct_pwr_device(struct gk20a *g,
85 void *pargs, u16 pargs_size, u8 type)
86{
87 struct boardobj *board_obj_ptr = NULL;
88 u32 status;
89 u32 indx;
90 struct pwr_device_ina3221 *pwrdev;
91 struct pwr_device_ina3221 *ina3221 = (struct pwr_device_ina3221*)pargs;
92
93 status = boardobj_construct_super(g, &board_obj_ptr,
94 pargs_size, pargs);
95 if (status)
96 return NULL;
97
98 pwrdev = (struct pwr_device_ina3221*)board_obj_ptr;
99
100 /* Set Super class interfaces */
101 board_obj_ptr->pmudatainit = _pwr_domains_pmudatainit_ina3221;
102 pwrdev->super.power_rail = ina3221->super.power_rail;
103 pwrdev->super.i2c_dev_idx = ina3221->super.i2c_dev_idx;
104 pwrdev->super.power_corr_factor = (1 << 12);
105 pwrdev->super.bIs_inforom_config = false;
106
107 /* Set INA3221-specific information */
108 pwrdev->configuration = ina3221->configuration;
109 pwrdev->mask_enable = ina3221->mask_enable;
110 pwrdev->gpio_function = ina3221->gpio_function;
111 pwrdev->curr_correct_m = ina3221->curr_correct_m;
112 pwrdev->curr_correct_b = ina3221->curr_correct_b;
113
114 for (indx = 0; indx < NV_PMU_PMGR_PWR_DEVICE_INA3221_CH_NUM; indx++) {
115 pwrdev->r_shuntm_ohm[indx] = ina3221->r_shuntm_ohm[indx];
116 }
117
118 gk20a_dbg_info(" Done");
119
120 return board_obj_ptr;
121}
122
123static u32 devinit_get_pwr_device_table(struct gk20a *g,
124 struct pwr_devices *ppwrdeviceobjs)
125{
126 u32 status = 0;
127 u8 *pwr_device_table_ptr = NULL;
128 u8 *curr_pwr_device_table_ptr = NULL;
129 struct boardobj *boardobj;
130 struct pwr_sensors_2x_header pwr_sensor_table_header = { 0 };
131 struct pwr_sensors_2x_entry pwr_sensor_table_entry = { 0 };
132 u32 index;
133 u32 obj_index = 0;
134 u16 pwr_device_size;
135 union {
136 struct boardobj boardobj;
137 struct pwr_device pwrdev;
138 struct pwr_device_ina3221 ina3221;
139 } pwr_device_data;
140
141 gk20a_dbg_info("");
142
143 if (g->ops.bios.get_perf_table_ptrs != NULL) {
144 pwr_device_table_ptr = (u8 *)g->ops.bios.get_perf_table_ptrs(g,
145 g->bios.perf_token, POWER_SENSORS_TABLE);
146 if (pwr_device_table_ptr == NULL) {
147 status = -EINVAL;
148 goto done;
149 }
150 }
151
152 memcpy(&pwr_sensor_table_header, pwr_device_table_ptr,
153 VBIOS_POWER_SENSORS_2X_HEADER_SIZE_08);
154
155 if (pwr_sensor_table_header.version !=
156 VBIOS_POWER_SENSORS_VERSION_2X) {
157 status = -EINVAL;
158 goto done;
159 }
160
161 if (pwr_sensor_table_header.header_size <
162 VBIOS_POWER_SENSORS_2X_HEADER_SIZE_08) {
163 status = -EINVAL;
164 goto done;
165 }
166
167 if (pwr_sensor_table_header.table_entry_size !=
168 VBIOS_POWER_SENSORS_2X_ENTRY_SIZE_15) {
169 status = -EINVAL;
170 goto done;
171 }
172
173 curr_pwr_device_table_ptr = (pwr_device_table_ptr +
174 VBIOS_POWER_SENSORS_2X_HEADER_SIZE_08);
175
176 for (index = 0; index < pwr_sensor_table_header.num_table_entries; index++) {
177 bool use_fxp8_8 = false;
178 u8 i2c_dev_idx;
179 u8 device_type;
180
181 curr_pwr_device_table_ptr += (pwr_sensor_table_header.table_entry_size * index);
182
183 pwr_sensor_table_entry.flags0 = *curr_pwr_device_table_ptr;
184
185 memcpy(&pwr_sensor_table_entry.class_param0,
186 (curr_pwr_device_table_ptr + 1),
187 (VBIOS_POWER_SENSORS_2X_ENTRY_SIZE_15 - 1));
188
189 device_type = (u8)BIOS_GET_FIELD(
190 pwr_sensor_table_entry.flags0,
191 NV_VBIOS_POWER_SENSORS_2X_ENTRY_FLAGS0_CLASS);
192
193 if (device_type == NV_VBIOS_POWER_SENSORS_2X_ENTRY_FLAGS0_CLASS_I2C) {
194 i2c_dev_idx = (u8)BIOS_GET_FIELD(
195 pwr_sensor_table_entry.class_param0,
196 NV_VBIOS_POWER_SENSORS_2X_ENTRY_CLASS_PARAM0_I2C_INDEX);
197 use_fxp8_8 = (u8)BIOS_GET_FIELD(
198 pwr_sensor_table_entry.class_param0,
199 NV_VBIOS_POWER_SENSORS_2X_ENTRY_CLASS_PARAM0_I2C_USE_FXP8_8);
200
201 pwr_device_data.ina3221.super.i2c_dev_idx = i2c_dev_idx;
202 pwr_device_data.ina3221.r_shuntm_ohm[0].use_fxp8_8 = use_fxp8_8;
203 pwr_device_data.ina3221.r_shuntm_ohm[1].use_fxp8_8 = use_fxp8_8;
204 pwr_device_data.ina3221.r_shuntm_ohm[2].use_fxp8_8 = use_fxp8_8;
205 pwr_device_data.ina3221.r_shuntm_ohm[0].rshunt_value =
206 (u16)BIOS_GET_FIELD(
207 pwr_sensor_table_entry.sensor_param0,
208 NV_VBIOS_POWER_SENSORS_2X_ENTRY_SENSOR_PARAM0_INA3221_RSHUNT0_MOHM);
209
210 pwr_device_data.ina3221.r_shuntm_ohm[1].rshunt_value =
211 (u16)BIOS_GET_FIELD(
212 pwr_sensor_table_entry.sensor_param0,
213 NV_VBIOS_POWER_SENSORS_2X_ENTRY_SENSOR_PARAM0_INA3221_RSHUNT1_MOHM);
214
215 pwr_device_data.ina3221.r_shuntm_ohm[2].rshunt_value =
216 (u16)BIOS_GET_FIELD(
217 pwr_sensor_table_entry.sensor_param1,
218 NV_VBIOS_POWER_SENSORS_2X_ENTRY_SENSOR_PARAM1_INA3221_RSHUNT2_MOHM);
219 pwr_device_data.ina3221.configuration =
220 (u16)BIOS_GET_FIELD(
221 pwr_sensor_table_entry.sensor_param1,
222 NV_VBIOS_POWER_SENSORS_2X_ENTRY_SENSOR_PARAM1_INA3221_CONFIGURATION);
223
224 pwr_device_data.ina3221.mask_enable =
225 (u16)BIOS_GET_FIELD(
226 pwr_sensor_table_entry.sensor_param2,
227 NV_VBIOS_POWER_SENSORS_2X_ENTRY_SENSOR_PARAM2_INA3221_MASKENABLE);
228
229 pwr_device_data.ina3221.gpio_function =
230 (u8)BIOS_GET_FIELD(
231 pwr_sensor_table_entry.sensor_param2,
232 NV_VBIOS_POWER_SENSORS_2X_ENTRY_SENSOR_PARAM2_INA3221_GPIOFUNCTION);
233
234 pwr_device_data.ina3221.curr_correct_m =
235 (u16)BIOS_GET_FIELD(
236 pwr_sensor_table_entry.sensor_param3,
237 NV_VBIOS_POWER_SENSORS_2X_ENTRY_SENSOR_PARAM3_INA3221_CURR_CORRECT_M);
238
239 pwr_device_data.ina3221.curr_correct_b =
240 (u16)BIOS_GET_FIELD(
241 pwr_sensor_table_entry.sensor_param3,
242 NV_VBIOS_POWER_SENSORS_2X_ENTRY_SENSOR_PARAM3_INA3221_CURR_CORRECT_B);
243
244 if (!pwr_device_data.ina3221.curr_correct_m) {
245 pwr_device_data.ina3221.curr_correct_m = (1 << 12);
246 }
247 pwr_device_size = sizeof(struct pwr_device_ina3221);
248 } else
249 continue;
250
251 pwr_device_data.boardobj.type = CTRL_PMGR_PWR_DEVICE_TYPE_INA3221;
252 pwr_device_data.pwrdev.power_rail = (u8)0;
253
254 boardobj = construct_pwr_device(g, &pwr_device_data,
255 pwr_device_size, pwr_device_data.boardobj.type);
256
257 if (!boardobj) {
258 gk20a_err(dev_from_gk20a(g),
259 "unable to create pwr device for %d type %d", index, pwr_device_data.boardobj.type);
260 status = -EINVAL;
261 goto done;
262 }
263
264 status = boardobjgrp_objinsert(&ppwrdeviceobjs->super.super,
265 boardobj, obj_index);
266
267 if (status) {
268 gk20a_err(dev_from_gk20a(g),
269 "unable to insert pwr device boardobj for %d", index);
270 status = -EINVAL;
271 goto done;
272 }
273
274 ++obj_index;
275 }
276
277done:
278 gk20a_dbg_info(" done status %x", status);
279 return status;
280}
281
282u32 pmgr_device_sw_setup(struct gk20a *g)
283{
284 u32 status;
285 struct boardobjgrp *pboardobjgrp = NULL;
286 struct pwr_devices *ppwrdeviceobjs;
287
288 /* Construct the Super Class and override the Interfaces */
289 status = boardobjgrpconstruct_e32(&g->pmgr_pmu.pmgr_deviceobjs.super);
290 if (status) {
291 gk20a_err(dev_from_gk20a(g),
292 "error creating boardobjgrp for pmgr devices, status - 0x%x",
293 status);
294 goto done;
295 }
296
297 pboardobjgrp = &g->pmgr_pmu.pmgr_deviceobjs.super.super;
298 ppwrdeviceobjs = &(g->pmgr_pmu.pmgr_deviceobjs);
299
300 /* Override the Interfaces */
301 pboardobjgrp->pmudatainstget = _pwr_device_pmudata_instget;
302
303 status = devinit_get_pwr_device_table(g, ppwrdeviceobjs);
304 if (status)
305 goto done;
306
307done:
308 gk20a_dbg_info(" done status %x", status);
309 return status;
310}