diff options
author | Deepak Nibade <dnibade@nvidia.com> | 2016-12-27 05:01:00 -0500 |
---|---|---|
committer | Deepak Nibade <dnibade@nvidia.com> | 2016-12-27 05:35:06 -0500 |
commit | 7a81883a0d70c3a43ad2841ac235f6dc344c60fb (patch) | |
tree | 92923d2efccf90d1961071fa9acde59178a0d688 /drivers/gpu/nvgpu/perf | |
parent | 505b442551a2e27aa3bc9e608c5a2bc9fccecbc4 (diff) | |
parent | 2aa3c85f8e82b3c07c39e677663abd3687c1822a (diff) |
Merge remote-tracking branch 'remotes/origin/dev/merge-nvgpu-t18x-into-nvgpu' into dev-kernel
Merge T186 - gp10b/gp106 code into common nvgpu repo
Bug 200266498
Change-Id: Ibf100ee38010cbed85c149b69b99147256f9a005
Signed-off-by: Deepak Nibade <dnibade@nvidia.com>
Diffstat (limited to 'drivers/gpu/nvgpu/perf')
-rw-r--r-- | drivers/gpu/nvgpu/perf/perf.c | 118 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/perf/perf.h | 66 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/perf/vfe_equ.c | 590 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/perf/vfe_equ.h | 76 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/perf/vfe_var.c | 1048 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/perf/vfe_var.h | 97 |
6 files changed, 1995 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/perf/perf.c b/drivers/gpu/nvgpu/perf/perf.c new file mode 100644 index 00000000..41ebb315 --- /dev/null +++ b/drivers/gpu/nvgpu/perf/perf.c | |||
@@ -0,0 +1,118 @@ | |||
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 "perf.h" | ||
16 | #include "pmuif/gpmuifperf.h" | ||
17 | #include "pmuif/gpmuifperfvfe.h" | ||
18 | #include "gk20a/pmu_gk20a.h" | ||
19 | #include "clk/clk_arb.h" | ||
20 | |||
21 | struct perfrpc_pmucmdhandler_params { | ||
22 | struct nv_pmu_perf_rpc *prpccall; | ||
23 | u32 success; | ||
24 | }; | ||
25 | |||
26 | static void perfrpc_pmucmdhandler(struct gk20a *g, struct pmu_msg *msg, | ||
27 | void *param, u32 handle, u32 status) | ||
28 | { | ||
29 | struct perfrpc_pmucmdhandler_params *phandlerparams = | ||
30 | (struct perfrpc_pmucmdhandler_params *)param; | ||
31 | |||
32 | gk20a_dbg_info(""); | ||
33 | |||
34 | if (msg->msg.perf.msg_type != NV_PMU_PERF_MSG_ID_RPC) { | ||
35 | gk20a_err(dev_from_gk20a(g), | ||
36 | "unsupported msg for VFE LOAD RPC %x", | ||
37 | msg->msg.perf.msg_type); | ||
38 | return; | ||
39 | } | ||
40 | |||
41 | if (phandlerparams->prpccall->b_supported) | ||
42 | phandlerparams->success = 1; | ||
43 | } | ||
44 | |||
45 | static int pmu_handle_perf_event(struct gk20a *g, void *pmu_msg) | ||
46 | { | ||
47 | struct nv_pmu_perf_msg *msg = (struct nv_pmu_perf_msg *)pmu_msg; | ||
48 | |||
49 | gk20a_dbg_fn(""); | ||
50 | switch (msg->msg_type) { | ||
51 | case NV_PMU_PERF_MSG_ID_VFE_CALLBACK: | ||
52 | nvgpu_clk_arb_schedule_vf_table_update(g); | ||
53 | break; | ||
54 | default: | ||
55 | WARN_ON(1); | ||
56 | break; | ||
57 | } | ||
58 | return 0; | ||
59 | } | ||
60 | |||
61 | u32 perf_pmu_vfe_load(struct gk20a *g) | ||
62 | { | ||
63 | struct pmu_cmd cmd; | ||
64 | struct pmu_msg msg; | ||
65 | struct pmu_payload payload = { {0} }; | ||
66 | u32 status; | ||
67 | u32 seqdesc; | ||
68 | struct nv_pmu_perf_rpc rpccall = {0}; | ||
69 | struct perfrpc_pmucmdhandler_params handler = {0}; | ||
70 | |||
71 | /*register call back for future VFE updates*/ | ||
72 | g->ops.perf.handle_pmu_perf_event = pmu_handle_perf_event; | ||
73 | |||
74 | rpccall.function = NV_PMU_PERF_RPC_ID_VFE_LOAD; | ||
75 | rpccall.params.vfe_load.b_load = true; | ||
76 | cmd.hdr.unit_id = PMU_UNIT_PERF; | ||
77 | cmd.hdr.size = (u32)sizeof(struct nv_pmu_perf_cmd) + | ||
78 | (u32)sizeof(struct pmu_hdr); | ||
79 | |||
80 | cmd.cmd.perf.cmd_type = NV_PMU_PERF_CMD_ID_RPC; | ||
81 | msg.hdr.size = sizeof(struct pmu_msg); | ||
82 | |||
83 | payload.in.buf = (u8 *)&rpccall; | ||
84 | payload.in.size = (u32)sizeof(struct nv_pmu_perf_rpc); | ||
85 | payload.in.fb_size = PMU_CMD_SUBMIT_PAYLOAD_PARAMS_FB_SIZE_UNUSED; | ||
86 | payload.in.offset = NV_PMU_PERF_CMD_RPC_ALLOC_OFFSET; | ||
87 | |||
88 | payload.out.buf = (u8 *)&rpccall; | ||
89 | payload.out.size = (u32)sizeof(struct nv_pmu_perf_rpc); | ||
90 | payload.out.fb_size = PMU_CMD_SUBMIT_PAYLOAD_PARAMS_FB_SIZE_UNUSED; | ||
91 | payload.out.offset = NV_PMU_PERF_MSG_RPC_ALLOC_OFFSET; | ||
92 | |||
93 | handler.prpccall = &rpccall; | ||
94 | handler.success = 0; | ||
95 | |||
96 | status = gk20a_pmu_cmd_post(g, &cmd, NULL, &payload, | ||
97 | PMU_COMMAND_QUEUE_LPQ, | ||
98 | perfrpc_pmucmdhandler, (void *)&handler, | ||
99 | &seqdesc, ~0); | ||
100 | |||
101 | if (status) { | ||
102 | gk20a_err(dev_from_gk20a(g), | ||
103 | "unable to post perf RPC cmd %x", | ||
104 | cmd.cmd.perf.cmd_type); | ||
105 | goto done; | ||
106 | } | ||
107 | |||
108 | pmu_wait_message_cond(&g->pmu, | ||
109 | gk20a_get_gr_idle_timeout(g), | ||
110 | &handler.success, 1); | ||
111 | |||
112 | if (handler.success == 0) { | ||
113 | status = -EINVAL; | ||
114 | gk20a_err(dev_from_gk20a(g), "rpc call to load VFE failed"); | ||
115 | } | ||
116 | done: | ||
117 | return status; | ||
118 | } | ||
diff --git a/drivers/gpu/nvgpu/perf/perf.h b/drivers/gpu/nvgpu/perf/perf.h new file mode 100644 index 00000000..a3213f7a --- /dev/null +++ b/drivers/gpu/nvgpu/perf/perf.h | |||
@@ -0,0 +1,66 @@ | |||
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 | #ifndef _PERF_H_ | ||
14 | #define _PERF_H_ | ||
15 | |||
16 | #include "vfe_equ.h" | ||
17 | #include "vfe_var.h" | ||
18 | #include "pstate/pstate.h" | ||
19 | #include "gk20a/gk20a.h" | ||
20 | #include "volt/volt.h" | ||
21 | #include "lpwr/lpwr.h" | ||
22 | |||
23 | #define CTRL_PERF_VFE_VAR_TYPE_INVALID 0x00 | ||
24 | #define CTRL_PERF_VFE_VAR_TYPE_DERIVED 0x01 | ||
25 | #define CTRL_PERF_VFE_VAR_TYPE_DERIVED_PRODUCT 0x02 | ||
26 | #define CTRL_PERF_VFE_VAR_TYPE_DERIVED_SUM 0x03 | ||
27 | #define CTRL_PERF_VFE_VAR_TYPE_SINGLE 0x04 | ||
28 | #define CTRL_PERF_VFE_VAR_TYPE_SINGLE_FREQUENCY 0x05 | ||
29 | #define CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED 0x06 | ||
30 | #define CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED_FUSE 0x07 | ||
31 | #define CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED_TEMP 0x08 | ||
32 | #define CTRL_PERF_VFE_VAR_TYPE_SINGLE_VOLTAGE 0x09 | ||
33 | |||
34 | #define CTRL_PERF_VFE_VAR_SINGLE_OVERRIDE_TYPE_NONE 0x00 | ||
35 | #define CTRL_PERF_VFE_VAR_SINGLE_OVERRIDE_TYPE_VALUE 0x01 | ||
36 | #define CTRL_PERF_VFE_VAR_SINGLE_OVERRIDE_TYPE_OFFSET 0x02 | ||
37 | #define CTRL_PERF_VFE_VAR_SINGLE_OVERRIDE_TYPE_SCALE 0x03 | ||
38 | |||
39 | #define CTRL_PERF_VFE_EQU_TYPE_INVALID 0x00 | ||
40 | #define CTRL_PERF_VFE_EQU_TYPE_COMPARE 0x01 | ||
41 | #define CTRL_PERF_VFE_EQU_TYPE_MINMAX 0x02 | ||
42 | #define CTRL_PERF_VFE_EQU_TYPE_QUADRATIC 0x03 | ||
43 | |||
44 | #define CTRL_PERF_VFE_EQU_OUTPUT_TYPE_UNITLESS 0x00 | ||
45 | #define CTRL_PERF_VFE_EQU_OUTPUT_TYPE_FREQ_MHZ 0x01 | ||
46 | #define CTRL_PERF_VFE_EQU_OUTPUT_TYPE_VOLT_UV 0x02 | ||
47 | #define CTRL_PERF_VFE_EQU_OUTPUT_TYPE_VF_GAIN 0x03 | ||
48 | #define CTRL_PERF_VFE_EQU_OUTPUT_TYPE_VOLT_DELTA_UV 0x04 | ||
49 | |||
50 | #define CTRL_PERF_VFE_EQU_QUADRATIC_COEFF_COUNT 0x03 | ||
51 | |||
52 | #define CTRL_PERF_VFE_EQU_COMPARE_FUNCTION_EQUAL 0x00 | ||
53 | #define CTRL_PERF_VFE_EQU_COMPARE_FUNCTION_GREATER_EQ 0x01 | ||
54 | #define CTRL_PERF_VFE_EQU_COMPARE_FUNCTION_GREATER 0x02 | ||
55 | |||
56 | struct perf_pmupstate { | ||
57 | struct vfe_vars vfe_varobjs; | ||
58 | struct vfe_equs vfe_equobjs; | ||
59 | struct pstates pstatesobjs; | ||
60 | struct obj_volt volt; | ||
61 | struct obj_lwpr lpwr; | ||
62 | }; | ||
63 | |||
64 | u32 perf_pmu_vfe_load(struct gk20a *g); | ||
65 | |||
66 | #endif | ||
diff --git a/drivers/gpu/nvgpu/perf/vfe_equ.c b/drivers/gpu/nvgpu/perf/vfe_equ.c new file mode 100644 index 00000000..6630fb21 --- /dev/null +++ b/drivers/gpu/nvgpu/perf/vfe_equ.c | |||
@@ -0,0 +1,590 @@ | |||
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 "perf.h" | ||
16 | #include "vfe_equ.h" | ||
17 | #include "include/bios.h" | ||
18 | #include "boardobj/boardobjgrp.h" | ||
19 | #include "boardobj/boardobjgrp_e255.h" | ||
20 | #include "pmuif/gpmuifboardobj.h" | ||
21 | #include "pmuif/gpmuifperf.h" | ||
22 | #include "pmuif/gpmuifperfvfe.h" | ||
23 | #include "gm206/bios_gm206.h" | ||
24 | #include "ctrl/ctrlclk.h" | ||
25 | #include "ctrl/ctrlvolt.h" | ||
26 | #include "gk20a/pmu_gk20a.h" | ||
27 | |||
28 | static struct vfe_equ *construct_vfe_equ(struct gk20a *g, void *pargs); | ||
29 | static u32 devinit_get_vfe_equ_table(struct gk20a *g, | ||
30 | struct vfe_equs *pequobjs); | ||
31 | |||
32 | static u32 _vfe_equs_pmudatainit(struct gk20a *g, | ||
33 | struct boardobjgrp *pboardobjgrp, | ||
34 | struct nv_pmu_boardobjgrp_super *pboardobjgrppmu) | ||
35 | { | ||
36 | u32 status = 0; | ||
37 | |||
38 | status = boardobjgrp_pmudatainit_e255(g, pboardobjgrp, pboardobjgrppmu); | ||
39 | if (status) { | ||
40 | gk20a_err(dev_from_gk20a(g), | ||
41 | "error updating pmu boardobjgrp for vfe equ 0x%x", | ||
42 | status); | ||
43 | goto done; | ||
44 | } | ||
45 | |||
46 | done: | ||
47 | return status; | ||
48 | } | ||
49 | |||
50 | static u32 _vfe_equs_pmudata_instget(struct gk20a *g, | ||
51 | struct nv_pmu_boardobjgrp *pmuboardobjgrp, | ||
52 | struct nv_pmu_boardobj **ppboardobjpmudata, | ||
53 | u8 idx) | ||
54 | { | ||
55 | struct nv_pmu_perf_vfe_equ_boardobj_grp_set *pgrp_set = | ||
56 | (struct nv_pmu_perf_vfe_equ_boardobj_grp_set *)pmuboardobjgrp; | ||
57 | |||
58 | gk20a_dbg_info(""); | ||
59 | |||
60 | /* check whether pmuboardobjgrp has a valid boardobj in index */ | ||
61 | if (idx >= CTRL_BOARDOBJGRP_E255_MAX_OBJECTS) | ||
62 | return -EINVAL; | ||
63 | |||
64 | *ppboardobjpmudata = (struct nv_pmu_boardobj *) | ||
65 | &pgrp_set->objects[idx].data.board_obj; | ||
66 | gk20a_dbg_info(" Done"); | ||
67 | return 0; | ||
68 | } | ||
69 | |||
70 | u32 vfe_equ_sw_setup(struct gk20a *g) | ||
71 | { | ||
72 | u32 status; | ||
73 | struct boardobjgrp *pboardobjgrp = NULL; | ||
74 | struct vfe_equs *pvfeequobjs; | ||
75 | |||
76 | gk20a_dbg_info(""); | ||
77 | |||
78 | status = boardobjgrpconstruct_e255(&g->perf_pmu.vfe_equobjs.super); | ||
79 | if (status) { | ||
80 | gk20a_err(dev_from_gk20a(g), | ||
81 | "error creating boardobjgrp for clk domain, status - 0x%x", | ||
82 | status); | ||
83 | goto done; | ||
84 | } | ||
85 | |||
86 | pboardobjgrp = &g->perf_pmu.vfe_equobjs.super.super; | ||
87 | pvfeequobjs = &(g->perf_pmu.vfe_equobjs); | ||
88 | |||
89 | BOARDOBJGRP_PMU_CONSTRUCT(pboardobjgrp, PERF, VFE_EQU); | ||
90 | |||
91 | status = BOARDOBJGRP_PMU_CMD_GRP_SET_CONSTRUCT(g, pboardobjgrp, | ||
92 | perf, PERF, vfe_equ, VFE_EQU); | ||
93 | if (status) { | ||
94 | gk20a_err(dev_from_gk20a(g), | ||
95 | "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x", | ||
96 | status); | ||
97 | goto done; | ||
98 | } | ||
99 | |||
100 | pboardobjgrp->pmudatainit = _vfe_equs_pmudatainit; | ||
101 | pboardobjgrp->pmudatainstget = _vfe_equs_pmudata_instget; | ||
102 | |||
103 | status = devinit_get_vfe_equ_table(g, pvfeequobjs); | ||
104 | if (status) | ||
105 | goto done; | ||
106 | |||
107 | done: | ||
108 | gk20a_dbg_info(" done status %x", status); | ||
109 | return status; | ||
110 | } | ||
111 | |||
112 | u32 vfe_equ_pmu_setup(struct gk20a *g) | ||
113 | { | ||
114 | u32 status; | ||
115 | struct boardobjgrp *pboardobjgrp = NULL; | ||
116 | |||
117 | gk20a_dbg_info(""); | ||
118 | |||
119 | pboardobjgrp = &g->perf_pmu.vfe_equobjs.super.super; | ||
120 | |||
121 | if (!pboardobjgrp->bconstructed) | ||
122 | return -EINVAL; | ||
123 | |||
124 | status = pboardobjgrp->pmuinithandle(g, pboardobjgrp); | ||
125 | |||
126 | gk20a_dbg_info("Done"); | ||
127 | return status; | ||
128 | } | ||
129 | |||
130 | static u32 devinit_get_vfe_equ_table(struct gk20a *g, | ||
131 | struct vfe_equs *pvfeequobjs) | ||
132 | { | ||
133 | u32 status = 0; | ||
134 | u8 *vfeequs_tbl_ptr = NULL; | ||
135 | struct vbios_vfe_3x_header_struct vfeequs_tbl_header = { 0 }; | ||
136 | struct vbios_vfe_3x_equ_entry_struct equ = { 0 }; | ||
137 | u8 *vfeequs_tbl_entry_ptr = NULL; | ||
138 | u8 *rd_offset_ptr = NULL; | ||
139 | u32 index = 0; | ||
140 | struct vfe_equ *pequ; | ||
141 | u8 equ_type = 0; | ||
142 | u32 szfmt; | ||
143 | union { | ||
144 | struct boardobj board_obj; | ||
145 | struct vfe_equ super; | ||
146 | struct vfe_equ_compare compare; | ||
147 | struct vfe_equ_minmax minmax; | ||
148 | struct vfe_equ_quadratic quadratic; | ||
149 | } equ_data; | ||
150 | |||
151 | gk20a_dbg_info(""); | ||
152 | |||
153 | if (g->ops.bios.get_perf_table_ptrs) { | ||
154 | vfeequs_tbl_ptr = (u8 *)g->ops.bios.get_perf_table_ptrs(g, | ||
155 | g->bios.perf_token, | ||
156 | CONTINUOUS_VIRTUAL_BINNING_TABLE); | ||
157 | if (vfeequs_tbl_ptr == NULL) { | ||
158 | status = -EINVAL; | ||
159 | goto done; | ||
160 | } | ||
161 | } | ||
162 | |||
163 | memcpy(&vfeequs_tbl_header, vfeequs_tbl_ptr, | ||
164 | VBIOS_CLOCKS_TABLE_1X_HEADER_SIZE_07); | ||
165 | if (vfeequs_tbl_header.header_size != VBIOS_CLOCKS_TABLE_1X_HEADER_SIZE_07) { | ||
166 | status = -EINVAL; | ||
167 | goto done; | ||
168 | } | ||
169 | |||
170 | if (vfeequs_tbl_header.vfe_equ_entry_size == | ||
171 | VBIOS_VFE_3X_EQU_ENTRY_SIZE_17) | ||
172 | szfmt = VBIOS_VFE_3X_EQU_ENTRY_SIZE_17; | ||
173 | else if (vfeequs_tbl_header.vfe_equ_entry_size == | ||
174 | VBIOS_VFE_3X_EQU_ENTRY_SIZE_18) | ||
175 | szfmt = VBIOS_VFE_3X_EQU_ENTRY_SIZE_18; | ||
176 | else { | ||
177 | status = -EINVAL; | ||
178 | goto done; | ||
179 | } | ||
180 | |||
181 | vfeequs_tbl_entry_ptr = vfeequs_tbl_ptr + | ||
182 | vfeequs_tbl_header.header_size + | ||
183 | (vfeequs_tbl_header.vfe_var_entry_count * | ||
184 | vfeequs_tbl_header.vfe_var_entry_size); | ||
185 | |||
186 | for (index = 0; | ||
187 | index < vfeequs_tbl_header.vfe_equ_entry_count; | ||
188 | index++) { | ||
189 | memset(&equ, 0, sizeof(struct vbios_vfe_3x_equ_entry_struct)); | ||
190 | |||
191 | rd_offset_ptr = vfeequs_tbl_entry_ptr + | ||
192 | (index * vfeequs_tbl_header.vfe_equ_entry_size); | ||
193 | |||
194 | memcpy(&equ, rd_offset_ptr, szfmt); | ||
195 | |||
196 | equ_data.super.var_idx = (u8)equ.var_idx; | ||
197 | equ_data.super.equ_idx_next = | ||
198 | (equ.equ_idx_next == VBIOS_VFE_3X_EQU_ENTRY_IDX_INVALID) ? | ||
199 | CTRL_BOARDOBJ_IDX_INVALID : (u8)equ.equ_idx_next; | ||
200 | equ_data.super.out_range_min = equ.out_range_min; | ||
201 | equ_data.super.out_range_max = equ.out_range_max; | ||
202 | |||
203 | switch (BIOS_GET_FIELD(equ.param3, VBIOS_VFE_3X_EQU_ENTRY_PAR3_OUTPUT_TYPE)) { | ||
204 | case VBIOS_VFE_3X_EQU_ENTRY_PAR3_OUTPUT_TYPE_UNITLESS: | ||
205 | equ_data.super.output_type = | ||
206 | CTRL_PERF_VFE_EQU_OUTPUT_TYPE_UNITLESS; | ||
207 | break; | ||
208 | |||
209 | case VBIOS_VFE_3X_EQU_ENTRY_PAR3_OUTPUT_TYPE_FREQ_MHZ: | ||
210 | equ_data.super.output_type = | ||
211 | CTRL_PERF_VFE_EQU_OUTPUT_TYPE_FREQ_MHZ; | ||
212 | break; | ||
213 | |||
214 | case VBIOS_VFE_3X_EQU_ENTRY_PAR3_OUTPUT_TYPE_VOLT_UV: | ||
215 | equ_data.super.output_type = | ||
216 | CTRL_PERF_VFE_EQU_OUTPUT_TYPE_VOLT_UV; | ||
217 | break; | ||
218 | |||
219 | case VBIOS_VFE_3X_EQU_ENTRY_PAR3_OUTPUT_TYPE_VF_GAIN: | ||
220 | equ_data.super.output_type = | ||
221 | CTRL_PERF_VFE_EQU_OUTPUT_TYPE_VF_GAIN; | ||
222 | break; | ||
223 | |||
224 | case VBIOS_VFE_3X_EQU_ENTRY_PAR3_OUTPUT_TYPE_VOLT_DELTA_UV: | ||
225 | equ_data.super.output_type = | ||
226 | CTRL_PERF_VFE_EQU_OUTPUT_TYPE_VOLT_DELTA_UV; | ||
227 | break; | ||
228 | |||
229 | default: | ||
230 | gk20a_err(dev_from_gk20a(g), | ||
231 | "unrecognized output id @vfeequ index %d", | ||
232 | index); | ||
233 | goto done; | ||
234 | } | ||
235 | |||
236 | switch ((u8)equ.type) { | ||
237 | case VBIOS_VFE_3X_EQU_ENTRY_TYPE_DISABLED: | ||
238 | case VBIOS_VFE_3X_EQU_ENTRY_TYPE_QUADRATIC_FXP: | ||
239 | case VBIOS_VFE_3X_EQU_ENTRY_TYPE_MINMAX_FXP: | ||
240 | continue; | ||
241 | break; | ||
242 | |||
243 | case VBIOS_VFE_3X_EQU_ENTRY_TYPE_QUADRATIC: | ||
244 | equ_type = CTRL_PERF_VFE_EQU_TYPE_QUADRATIC; | ||
245 | equ_data.quadratic.coeffs[0] = equ.param0; | ||
246 | equ_data.quadratic.coeffs[1] = equ.param1; | ||
247 | equ_data.quadratic.coeffs[2] = equ.param2; | ||
248 | break; | ||
249 | |||
250 | case VBIOS_VFE_3X_EQU_ENTRY_TYPE_MINMAX: | ||
251 | equ_type = CTRL_PERF_VFE_EQU_TYPE_MINMAX; | ||
252 | equ_data.minmax.b_max = BIOS_GET_FIELD(equ.param0, | ||
253 | VBIOS_VFE_3X_EQU_ENTRY_PAR0_MINMAX_CRIT) && | ||
254 | VBIOS_VFE_3X_EQU_ENTRY_PAR0_MINMAX_CRIT_MAX; | ||
255 | equ_data.minmax.equ_idx0 = (u8)BIOS_GET_FIELD( | ||
256 | equ.param0, | ||
257 | VBIOS_VFE_3X_EQU_ENTRY_PAR0_MINMAX_VFE_EQU_IDX_0); | ||
258 | equ_data.minmax.equ_idx1 = (u8)BIOS_GET_FIELD( | ||
259 | equ.param0, | ||
260 | VBIOS_VFE_3X_EQU_ENTRY_PAR0_MINMAX_VFE_EQU_IDX_1); | ||
261 | break; | ||
262 | |||
263 | case VBIOS_VFE_3X_EQU_ENTRY_TYPE_COMPARE: | ||
264 | { | ||
265 | u8 cmp_func = (u8)BIOS_GET_FIELD( | ||
266 | equ.param1, | ||
267 | VBIOS_VFE_3X_EQU_ENTRY_PAR1_COMPARE_FUNCTION); | ||
268 | equ_type = CTRL_PERF_VFE_EQU_TYPE_COMPARE; | ||
269 | |||
270 | switch (cmp_func) { | ||
271 | case VBIOS_VFE_3X_EQU_ENTRY_PAR1_COMPARE_FUNCTION_EQUAL: | ||
272 | equ_data.compare.func_id = | ||
273 | CTRL_PERF_VFE_EQU_COMPARE_FUNCTION_EQUAL; | ||
274 | break; | ||
275 | |||
276 | case VBIOS_VFE_3X_EQU_ENTRY_PAR1_COMPARE_FUNCTION_GREATER_EQ: | ||
277 | equ_data.compare.func_id = | ||
278 | CTRL_PERF_VFE_EQU_COMPARE_FUNCTION_GREATER_EQ; | ||
279 | break; | ||
280 | case VBIOS_VFE_3X_EQU_ENTRY_PAR1_COMPARE_FUNCTION_GREATER: | ||
281 | equ_data.compare.func_id = | ||
282 | CTRL_PERF_VFE_EQU_COMPARE_FUNCTION_GREATER; | ||
283 | break; | ||
284 | default: | ||
285 | gk20a_err(dev_from_gk20a(g), | ||
286 | "invalid vfe compare index %x type %x ", | ||
287 | index, cmp_func); | ||
288 | status = -EINVAL; | ||
289 | goto done; | ||
290 | } | ||
291 | equ_data.compare.equ_idx_true = (u8)BIOS_GET_FIELD( | ||
292 | equ.param1, | ||
293 | VBIOS_VFE_3X_EQU_ENTRY_PAR1_COMPARE_VFE_EQU_IDX_TRUE); | ||
294 | equ_data.compare.equ_idx_false = (u8)BIOS_GET_FIELD( | ||
295 | equ.param1, | ||
296 | VBIOS_VFE_3X_EQU_ENTRY_PAR1_COMPARE_VFE_EQU_IDX_FALSE); | ||
297 | equ_data.compare.criteria = equ.param0; | ||
298 | break; | ||
299 | } | ||
300 | default: | ||
301 | status = -EINVAL; | ||
302 | gk20a_err(dev_from_gk20a(g), | ||
303 | "Invalid equ[%d].type = 0x%x.", | ||
304 | index, (u8)equ.type); | ||
305 | goto done; | ||
306 | } | ||
307 | |||
308 | equ_data.board_obj.type = equ_type; | ||
309 | pequ = construct_vfe_equ(g, (void *)&equ_data); | ||
310 | |||
311 | if (pequ == NULL) { | ||
312 | gk20a_err(dev_from_gk20a(g), | ||
313 | "error constructing vfe_equ boardobj %d", index); | ||
314 | status = -EINVAL; | ||
315 | goto done; | ||
316 | } | ||
317 | |||
318 | status = boardobjgrp_objinsert(&pvfeequobjs->super.super, | ||
319 | (struct boardobj *)pequ, index); | ||
320 | if (status) { | ||
321 | gk20a_err(dev_from_gk20a(g), | ||
322 | "error adding vfe_equ boardobj %d", index); | ||
323 | status = -EINVAL; | ||
324 | goto done; | ||
325 | } | ||
326 | } | ||
327 | done: | ||
328 | gk20a_dbg_info(" done status %x", status); | ||
329 | return status; | ||
330 | } | ||
331 | |||
332 | static u32 _vfe_equ_pmudatainit_super(struct gk20a *g, | ||
333 | struct boardobj *board_obj_ptr, | ||
334 | struct nv_pmu_boardobj *ppmudata) | ||
335 | { | ||
336 | u32 status = 0; | ||
337 | struct vfe_equ *pvfe_equ; | ||
338 | struct nv_pmu_vfe_equ *pset; | ||
339 | |||
340 | gk20a_dbg_info(""); | ||
341 | |||
342 | status = boardobj_pmudatainit_super(g, board_obj_ptr, ppmudata); | ||
343 | if (status != 0) | ||
344 | return status; | ||
345 | |||
346 | pvfe_equ = (struct vfe_equ *)board_obj_ptr; | ||
347 | |||
348 | pset = (struct nv_pmu_vfe_equ *) | ||
349 | ppmudata; | ||
350 | |||
351 | pset->var_idx = pvfe_equ->var_idx; | ||
352 | pset->equ_idx_next = pvfe_equ->equ_idx_next; | ||
353 | pset->output_type = pvfe_equ->output_type; | ||
354 | pset->out_range_min = pvfe_equ->out_range_min; | ||
355 | pset->out_range_max = pvfe_equ->out_range_max; | ||
356 | |||
357 | return status; | ||
358 | } | ||
359 | |||
360 | static u32 vfe_equ_construct_super(struct gk20a *g, | ||
361 | struct boardobj **ppboardobj, | ||
362 | u16 size, void *pargs) | ||
363 | { | ||
364 | struct vfe_equ *pvfeequ; | ||
365 | struct vfe_equ *ptmpequ = (struct vfe_equ *)pargs; | ||
366 | u32 status = 0; | ||
367 | |||
368 | status = boardobj_construct_super(g, ppboardobj, | ||
369 | size, pargs); | ||
370 | if (status) | ||
371 | return -EINVAL; | ||
372 | |||
373 | pvfeequ = (struct vfe_equ *)*ppboardobj; | ||
374 | |||
375 | pvfeequ->super.pmudatainit = | ||
376 | _vfe_equ_pmudatainit_super; | ||
377 | |||
378 | pvfeequ->var_idx = ptmpequ->var_idx; | ||
379 | pvfeequ->equ_idx_next = ptmpequ->equ_idx_next; | ||
380 | pvfeequ->output_type = ptmpequ->output_type; | ||
381 | pvfeequ->out_range_min = ptmpequ->out_range_min; | ||
382 | pvfeequ->out_range_max = ptmpequ->out_range_max; | ||
383 | |||
384 | return status; | ||
385 | } | ||
386 | |||
387 | static u32 _vfe_equ_pmudatainit_compare(struct gk20a *g, | ||
388 | struct boardobj *board_obj_ptr, | ||
389 | struct nv_pmu_boardobj *ppmudata) | ||
390 | { | ||
391 | u32 status = 0; | ||
392 | struct vfe_equ_compare *pvfe_equ_compare; | ||
393 | struct nv_pmu_vfe_equ_compare *pset; | ||
394 | |||
395 | gk20a_dbg_info(""); | ||
396 | |||
397 | status = _vfe_equ_pmudatainit_super(g, board_obj_ptr, ppmudata); | ||
398 | if (status != 0) | ||
399 | return status; | ||
400 | |||
401 | pvfe_equ_compare = (struct vfe_equ_compare *)board_obj_ptr; | ||
402 | |||
403 | pset = (struct nv_pmu_vfe_equ_compare *) ppmudata; | ||
404 | |||
405 | pset->func_id = pvfe_equ_compare->func_id; | ||
406 | pset->equ_idx_true = pvfe_equ_compare->equ_idx_true; | ||
407 | pset->equ_idx_false = pvfe_equ_compare->equ_idx_false; | ||
408 | pset->criteria = pvfe_equ_compare->criteria; | ||
409 | |||
410 | return status; | ||
411 | } | ||
412 | |||
413 | |||
414 | static u32 vfe_equ_construct_compare(struct gk20a *g, | ||
415 | struct boardobj **ppboardobj, | ||
416 | u16 size, void *pargs) | ||
417 | { | ||
418 | struct boardobj *ptmpobj = (struct boardobj *)pargs; | ||
419 | struct vfe_equ_compare *pvfeequ; | ||
420 | struct vfe_equ_compare *ptmpequ = | ||
421 | (struct vfe_equ_compare *)pargs; | ||
422 | u32 status = 0; | ||
423 | |||
424 | if (BOARDOBJ_GET_TYPE(pargs) != CTRL_PERF_VFE_EQU_TYPE_COMPARE) | ||
425 | return -EINVAL; | ||
426 | |||
427 | ptmpobj->type_mask |= BIT(CTRL_PERF_VFE_EQU_TYPE_COMPARE); | ||
428 | status = vfe_equ_construct_super(g, ppboardobj, size, pargs); | ||
429 | if (status) | ||
430 | return -EINVAL; | ||
431 | |||
432 | pvfeequ = (struct vfe_equ_compare *)*ppboardobj; | ||
433 | |||
434 | pvfeequ->super.super.pmudatainit = | ||
435 | _vfe_equ_pmudatainit_compare; | ||
436 | |||
437 | pvfeequ->func_id = ptmpequ->func_id; | ||
438 | pvfeequ->equ_idx_true = ptmpequ->equ_idx_true; | ||
439 | pvfeequ->equ_idx_false = ptmpequ->equ_idx_false; | ||
440 | pvfeequ->criteria = ptmpequ->criteria; | ||
441 | |||
442 | |||
443 | return status; | ||
444 | } | ||
445 | |||
446 | static u32 _vfe_equ_pmudatainit_minmax(struct gk20a *g, | ||
447 | struct boardobj *board_obj_ptr, | ||
448 | struct nv_pmu_boardobj *ppmudata) | ||
449 | { | ||
450 | u32 status = 0; | ||
451 | struct vfe_equ_minmax *pvfe_equ_minmax; | ||
452 | struct nv_pmu_vfe_equ_minmax *pset; | ||
453 | |||
454 | gk20a_dbg_info(""); | ||
455 | |||
456 | status = _vfe_equ_pmudatainit_super(g, board_obj_ptr, ppmudata); | ||
457 | if (status != 0) | ||
458 | return status; | ||
459 | |||
460 | pvfe_equ_minmax = (struct vfe_equ_minmax *)board_obj_ptr; | ||
461 | |||
462 | pset = (struct nv_pmu_vfe_equ_minmax *) | ||
463 | ppmudata; | ||
464 | |||
465 | pset->b_max = pvfe_equ_minmax->b_max; | ||
466 | pset->equ_idx0 = pvfe_equ_minmax->equ_idx0; | ||
467 | pset->equ_idx1 = pvfe_equ_minmax->equ_idx1; | ||
468 | |||
469 | return status; | ||
470 | } | ||
471 | |||
472 | static u32 vfe_equ_construct_minmax(struct gk20a *g, | ||
473 | struct boardobj **ppboardobj, | ||
474 | u16 size, void *pargs) | ||
475 | { | ||
476 | struct boardobj *ptmpobj = (struct boardobj *)pargs; | ||
477 | struct vfe_equ_minmax *pvfeequ; | ||
478 | struct vfe_equ_minmax *ptmpequ = | ||
479 | (struct vfe_equ_minmax *)pargs; | ||
480 | u32 status = 0; | ||
481 | |||
482 | if (BOARDOBJ_GET_TYPE(pargs) != CTRL_PERF_VFE_EQU_TYPE_MINMAX) | ||
483 | return -EINVAL; | ||
484 | |||
485 | ptmpobj->type_mask |= BIT(CTRL_PERF_VFE_EQU_TYPE_MINMAX); | ||
486 | status = vfe_equ_construct_super(g, ppboardobj, size, pargs); | ||
487 | if (status) | ||
488 | return -EINVAL; | ||
489 | |||
490 | pvfeequ = (struct vfe_equ_minmax *)*ppboardobj; | ||
491 | |||
492 | pvfeequ->super.super.pmudatainit = | ||
493 | _vfe_equ_pmudatainit_minmax; | ||
494 | pvfeequ->b_max = ptmpequ->b_max; | ||
495 | pvfeequ->equ_idx0 = ptmpequ->equ_idx0; | ||
496 | pvfeequ->equ_idx1 = ptmpequ->equ_idx1; | ||
497 | |||
498 | return status; | ||
499 | } | ||
500 | |||
501 | static u32 _vfe_equ_pmudatainit_quadratic(struct gk20a *g, | ||
502 | struct boardobj *board_obj_ptr, | ||
503 | struct nv_pmu_boardobj *ppmudata) | ||
504 | { | ||
505 | u32 status = 0; | ||
506 | struct vfe_equ_quadratic *pvfe_equ_quadratic; | ||
507 | struct nv_pmu_vfe_equ_quadratic *pset; | ||
508 | u32 i; | ||
509 | |||
510 | gk20a_dbg_info(""); | ||
511 | |||
512 | status = _vfe_equ_pmudatainit_super(g, board_obj_ptr, ppmudata); | ||
513 | if (status != 0) | ||
514 | return status; | ||
515 | |||
516 | pvfe_equ_quadratic = (struct vfe_equ_quadratic *)board_obj_ptr; | ||
517 | |||
518 | pset = (struct nv_pmu_vfe_equ_quadratic *) ppmudata; | ||
519 | |||
520 | for (i = 0; i < CTRL_PERF_VFE_EQU_QUADRATIC_COEFF_COUNT; i++) | ||
521 | pset->coeffs[i] = pvfe_equ_quadratic->coeffs[i]; | ||
522 | |||
523 | return status; | ||
524 | } | ||
525 | |||
526 | static u32 vfe_equ_construct_quadratic(struct gk20a *g, | ||
527 | struct boardobj **ppboardobj, | ||
528 | u16 size, void *pargs) | ||
529 | { | ||
530 | struct boardobj *ptmpobj = (struct boardobj *)pargs; | ||
531 | struct vfe_equ_quadratic *pvfeequ; | ||
532 | struct vfe_equ_quadratic *ptmpequ = | ||
533 | (struct vfe_equ_quadratic *)pargs; | ||
534 | u32 status = 0; | ||
535 | u32 i; | ||
536 | |||
537 | if (BOARDOBJ_GET_TYPE(pargs) != CTRL_PERF_VFE_EQU_TYPE_QUADRATIC) | ||
538 | return -EINVAL; | ||
539 | |||
540 | ptmpobj->type_mask |= BIT(CTRL_PERF_VFE_EQU_TYPE_QUADRATIC); | ||
541 | status = vfe_equ_construct_super(g, ppboardobj, size, pargs); | ||
542 | if (status) | ||
543 | return -EINVAL; | ||
544 | |||
545 | pvfeequ = (struct vfe_equ_quadratic *)*ppboardobj; | ||
546 | |||
547 | pvfeequ->super.super.pmudatainit = | ||
548 | _vfe_equ_pmudatainit_quadratic; | ||
549 | |||
550 | for (i = 0; i < CTRL_PERF_VFE_EQU_QUADRATIC_COEFF_COUNT; i++) | ||
551 | pvfeequ->coeffs[i] = ptmpequ->coeffs[i]; | ||
552 | |||
553 | return status; | ||
554 | } | ||
555 | |||
556 | static struct vfe_equ *construct_vfe_equ(struct gk20a *g, void *pargs) | ||
557 | { | ||
558 | struct boardobj *board_obj_ptr = NULL; | ||
559 | u32 status; | ||
560 | |||
561 | gk20a_dbg_info(""); | ||
562 | |||
563 | switch (BOARDOBJ_GET_TYPE(pargs)) { | ||
564 | case CTRL_PERF_VFE_EQU_TYPE_COMPARE: | ||
565 | status = vfe_equ_construct_compare(g, &board_obj_ptr, | ||
566 | sizeof(struct vfe_equ_compare), pargs); | ||
567 | break; | ||
568 | |||
569 | case CTRL_PERF_VFE_EQU_TYPE_MINMAX: | ||
570 | status = vfe_equ_construct_minmax(g, &board_obj_ptr, | ||
571 | sizeof(struct vfe_equ_minmax), pargs); | ||
572 | break; | ||
573 | |||
574 | case CTRL_PERF_VFE_EQU_TYPE_QUADRATIC: | ||
575 | status = vfe_equ_construct_quadratic(g, &board_obj_ptr, | ||
576 | sizeof(struct vfe_equ_quadratic), pargs); | ||
577 | break; | ||
578 | |||
579 | default: | ||
580 | return NULL; | ||
581 | |||
582 | } | ||
583 | |||
584 | if (status) | ||
585 | return NULL; | ||
586 | |||
587 | gk20a_dbg_info(" Done"); | ||
588 | |||
589 | return (struct vfe_equ *)board_obj_ptr; | ||
590 | } | ||
diff --git a/drivers/gpu/nvgpu/perf/vfe_equ.h b/drivers/gpu/nvgpu/perf/vfe_equ.h new file mode 100644 index 00000000..8aaddccd --- /dev/null +++ b/drivers/gpu/nvgpu/perf/vfe_equ.h | |||
@@ -0,0 +1,76 @@ | |||
1 | /* | ||
2 | * general perf structures & definitions | ||
3 | * | ||
4 | * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | */ | ||
15 | #ifndef _VFE_EQU_H_ | ||
16 | #define _VFE_EQU_H_ | ||
17 | |||
18 | #include "boardobj/boardobjgrp.h" | ||
19 | #include "perf/vfe_var.h" | ||
20 | #include "pmuif/gpmuifperf.h" | ||
21 | #include "pmuif/gpmuifperfvfe.h" | ||
22 | |||
23 | u32 vfe_equ_sw_setup(struct gk20a *g); | ||
24 | u32 vfe_equ_pmu_setup(struct gk20a *g); | ||
25 | |||
26 | #define VFE_EQU_GET(_pperf, _idx) \ | ||
27 | ((struct vfe_equ *)BOARDOBJGRP_OBJ_GET_BY_IDX( \ | ||
28 | &((_pperf)->vfe.equs.super.super), (_idx))) | ||
29 | |||
30 | #define VFE_EQU_IDX_IS_VALID(_pperf, _idx) \ | ||
31 | boardobjgrp_idxisvalid(&((_pperf)->vfe.equs.super.super), (_idx)) | ||
32 | |||
33 | #define VFE_EQU_OUTPUT_TYPE_IS_VALID(_pperf, _idx, _outputtype) \ | ||
34 | (VFE_EQU_IDX_IS_VALID((_pperf), (_idx)) && \ | ||
35 | ((_outputtype) != CTRL_PERF_VFE_EQU_OUTPUT_TYPE_UNITLESS) && \ | ||
36 | ((VFE_EQU_GET((_pperf), (_idx))->outputtype == (_outputtype)) || \ | ||
37 | (VFE_EQU_GET((_pperf), (_idx))->outputtype == \ | ||
38 | CTRL_PERF_VFE_EQU_OUTPUT_TYPE_UNITLESS))) | ||
39 | |||
40 | struct vfe_equ { | ||
41 | struct boardobj super; | ||
42 | u8 var_idx; | ||
43 | u8 equ_idx_next; | ||
44 | u8 output_type; | ||
45 | u32 out_range_min; | ||
46 | u32 out_range_max; | ||
47 | |||
48 | bool b_is_dynamic_valid; | ||
49 | bool b_is_dynamic; | ||
50 | }; | ||
51 | |||
52 | struct vfe_equs { | ||
53 | struct boardobjgrp_e255 super; | ||
54 | }; | ||
55 | |||
56 | struct vfe_equ_compare { | ||
57 | struct vfe_equ super; | ||
58 | u8 func_id; | ||
59 | u8 equ_idx_true; | ||
60 | u8 equ_idx_false; | ||
61 | u32 criteria; | ||
62 | }; | ||
63 | |||
64 | struct vfe_equ_minmax { | ||
65 | struct vfe_equ super; | ||
66 | bool b_max; | ||
67 | u8 equ_idx0; | ||
68 | u8 equ_idx1; | ||
69 | }; | ||
70 | |||
71 | struct vfe_equ_quadratic { | ||
72 | struct vfe_equ super; | ||
73 | u32 coeffs[CTRL_PERF_VFE_EQU_QUADRATIC_COEFF_COUNT]; | ||
74 | }; | ||
75 | |||
76 | #endif | ||
diff --git a/drivers/gpu/nvgpu/perf/vfe_var.c b/drivers/gpu/nvgpu/perf/vfe_var.c new file mode 100644 index 00000000..4f8dc83b --- /dev/null +++ b/drivers/gpu/nvgpu/perf/vfe_var.c | |||
@@ -0,0 +1,1048 @@ | |||
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 "perf.h" | ||
16 | #include "vfe_var.h" | ||
17 | #include "include/bios.h" | ||
18 | #include "boardobj/boardobjgrp.h" | ||
19 | #include "boardobj/boardobjgrp_e32.h" | ||
20 | #include "pmuif/gpmuifboardobj.h" | ||
21 | #include "pmuif/gpmuifperf.h" | ||
22 | #include "pmuif/gpmuifperfvfe.h" | ||
23 | #include "gm206/bios_gm206.h" | ||
24 | #include "ctrl/ctrlclk.h" | ||
25 | #include "ctrl/ctrlvolt.h" | ||
26 | #include "gk20a/pmu_gk20a.h" | ||
27 | |||
28 | static u32 devinit_get_vfe_var_table(struct gk20a *g, | ||
29 | struct vfe_vars *pvarobjs); | ||
30 | static u32 vfe_var_construct_single(struct gk20a *g, | ||
31 | struct boardobj **ppboardobj, | ||
32 | u16 size, void *pargs); | ||
33 | |||
34 | static u32 _vfe_vars_pmudatainit(struct gk20a *g, | ||
35 | struct boardobjgrp *pboardobjgrp, | ||
36 | struct nv_pmu_boardobjgrp_super *pboardobjgrppmu) | ||
37 | { | ||
38 | struct nv_pmu_perf_vfe_var_boardobjgrp_set_header *pset = | ||
39 | (struct nv_pmu_perf_vfe_var_boardobjgrp_set_header *) | ||
40 | pboardobjgrppmu; | ||
41 | struct vfe_vars *pvars = (struct vfe_vars *)pboardobjgrp; | ||
42 | u32 status = 0; | ||
43 | |||
44 | status = boardobjgrp_pmudatainit_e32(g, pboardobjgrp, pboardobjgrppmu); | ||
45 | if (status) { | ||
46 | gk20a_err(dev_from_gk20a(g), | ||
47 | "error updating pmu boardobjgrp for vfe var 0x%x", | ||
48 | status); | ||
49 | goto done; | ||
50 | } | ||
51 | pset->polling_periodms = pvars->polling_periodms; | ||
52 | |||
53 | done: | ||
54 | return status; | ||
55 | } | ||
56 | |||
57 | static u32 _vfe_vars_pmudata_instget(struct gk20a *g, | ||
58 | struct nv_pmu_boardobjgrp *pmuboardobjgrp, | ||
59 | struct nv_pmu_boardobj **ppboardobjpmudata, | ||
60 | u8 idx) | ||
61 | { | ||
62 | struct nv_pmu_perf_vfe_var_boardobj_grp_set *pgrp_set = | ||
63 | (struct nv_pmu_perf_vfe_var_boardobj_grp_set *) | ||
64 | pmuboardobjgrp; | ||
65 | |||
66 | gk20a_dbg_info(""); | ||
67 | |||
68 | /*check whether pmuboardobjgrp has a valid boardobj in index*/ | ||
69 | if (idx >= CTRL_BOARDOBJGRP_E32_MAX_OBJECTS) | ||
70 | return -EINVAL; | ||
71 | |||
72 | *ppboardobjpmudata = (struct nv_pmu_boardobj *) | ||
73 | &pgrp_set->objects[idx].data.board_obj; | ||
74 | |||
75 | gk20a_dbg_info(" Done"); | ||
76 | return 0; | ||
77 | } | ||
78 | |||
79 | static u32 _vfe_vars_pmustatus_instget(struct gk20a *g, void *pboardobjgrppmu, | ||
80 | struct nv_pmu_boardobj_query **ppboardobjpmustatus, u8 idx) | ||
81 | { | ||
82 | struct nv_pmu_perf_vfe_var_boardobj_grp_get_status *pgrp_get_status = | ||
83 | (struct nv_pmu_perf_vfe_var_boardobj_grp_get_status *) | ||
84 | pboardobjgrppmu; | ||
85 | |||
86 | if (((u32)BIT(idx) & | ||
87 | pgrp_get_status->hdr.data.super.obj_mask.super.data[0]) == 0) | ||
88 | return -EINVAL; | ||
89 | |||
90 | *ppboardobjpmustatus = (struct nv_pmu_boardobj_query *) | ||
91 | &pgrp_get_status->objects[idx].data.board_obj; | ||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | |||
96 | u32 vfe_var_sw_setup(struct gk20a *g) | ||
97 | { | ||
98 | u32 status; | ||
99 | struct boardobjgrp *pboardobjgrp = NULL; | ||
100 | struct vfe_vars *pvfevarobjs; | ||
101 | |||
102 | gk20a_dbg_info(""); | ||
103 | |||
104 | status = boardobjgrpconstruct_e32(&g->perf_pmu.vfe_varobjs.super); | ||
105 | if (status) { | ||
106 | gk20a_err(dev_from_gk20a(g), | ||
107 | "error creating boardobjgrp for clk domain, status - 0x%x", | ||
108 | status); | ||
109 | goto done; | ||
110 | } | ||
111 | |||
112 | pboardobjgrp = &g->perf_pmu.vfe_varobjs.super.super; | ||
113 | pvfevarobjs = &g->perf_pmu.vfe_varobjs; | ||
114 | |||
115 | BOARDOBJGRP_PMU_CONSTRUCT(pboardobjgrp, PERF, VFE_VAR); | ||
116 | |||
117 | status = BOARDOBJGRP_PMU_CMD_GRP_SET_CONSTRUCT(g, pboardobjgrp, | ||
118 | perf, PERF, vfe_var, VFE_VAR); | ||
119 | if (status) { | ||
120 | gk20a_err(dev_from_gk20a(g), | ||
121 | "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x", | ||
122 | status); | ||
123 | goto done; | ||
124 | } | ||
125 | |||
126 | pboardobjgrp->pmudatainit = _vfe_vars_pmudatainit; | ||
127 | pboardobjgrp->pmudatainstget = _vfe_vars_pmudata_instget; | ||
128 | pboardobjgrp->pmustatusinstget = _vfe_vars_pmustatus_instget; | ||
129 | |||
130 | status = devinit_get_vfe_var_table(g, pvfevarobjs); | ||
131 | if (status) | ||
132 | goto done; | ||
133 | |||
134 | status = BOARDOBJGRP_PMU_CMD_GRP_GET_STATUS_CONSTRUCT(g, | ||
135 | &g->perf_pmu.vfe_varobjs.super.super, | ||
136 | perf, PERF, vfe_var, VFE_VAR); | ||
137 | if (status) { | ||
138 | gk20a_err(dev_from_gk20a(g), | ||
139 | "error constructing PMU_BOARDOBJ_CMD_GRP_GET_STATUS interface - 0x%x", | ||
140 | status); | ||
141 | goto done; | ||
142 | } | ||
143 | |||
144 | done: | ||
145 | gk20a_dbg_info(" done status %x", status); | ||
146 | return status; | ||
147 | } | ||
148 | |||
149 | u32 vfe_var_pmu_setup(struct gk20a *g) | ||
150 | { | ||
151 | u32 status; | ||
152 | struct boardobjgrp *pboardobjgrp = NULL; | ||
153 | |||
154 | gk20a_dbg_info(""); | ||
155 | |||
156 | pboardobjgrp = &g->perf_pmu.vfe_varobjs.super.super; | ||
157 | |||
158 | if (!pboardobjgrp->bconstructed) | ||
159 | return -EINVAL; | ||
160 | |||
161 | status = pboardobjgrp->pmuinithandle(g, pboardobjgrp); | ||
162 | |||
163 | gk20a_dbg_info("Done"); | ||
164 | return status; | ||
165 | } | ||
166 | |||
167 | u32 dev_init_get_vfield_info(struct gk20a *g, | ||
168 | struct vfe_var_single_sensed_fuse *pvfevar) | ||
169 | { | ||
170 | u8 *vfieldtableptr = NULL; | ||
171 | u32 vfieldheadersize = VFIELD_HEADER_SIZE; | ||
172 | u8 *vfieldregtableptr = NULL; | ||
173 | u32 vfieldregheadersize = VFIELD_REG_HEADER_SIZE; | ||
174 | u32 i; | ||
175 | u32 oldindex = 0xFFFFFFFF; | ||
176 | u32 currindex; | ||
177 | struct vfield_reg_header vregheader; | ||
178 | struct vfield_reg_entry vregentry; | ||
179 | struct vfield_header vheader; | ||
180 | struct vfield_entry ventry; | ||
181 | union nv_pmu_bios_vfield_register_segment *psegment = NULL; | ||
182 | u8 *psegmentcount = NULL; | ||
183 | u32 status = 0; | ||
184 | |||
185 | if (g->ops.bios.get_perf_table_ptrs) { | ||
186 | vfieldregtableptr = (u8 *)g->ops.bios.get_perf_table_ptrs(g, | ||
187 | g->bios.virt_token, VP_FIELD_REGISTER); | ||
188 | if (vfieldregtableptr == NULL) { | ||
189 | status = -EINVAL; | ||
190 | goto done; | ||
191 | } | ||
192 | |||
193 | vfieldtableptr = (u8 *)g->ops.bios.get_perf_table_ptrs(g, | ||
194 | g->bios.virt_token, VP_FIELD_TABLE); | ||
195 | if (vfieldtableptr == NULL) { | ||
196 | status = -EINVAL; | ||
197 | goto done; | ||
198 | } | ||
199 | } | ||
200 | |||
201 | memcpy(&vregheader, vfieldregtableptr, VFIELD_REG_HEADER_SIZE); | ||
202 | |||
203 | if (vregheader.version != VBIOS_VFIELD_REG_TABLE_VERSION_1_0) { | ||
204 | gk20a_err(dev_from_gk20a(g), "invalid vreg header version"); | ||
205 | goto done; | ||
206 | } | ||
207 | |||
208 | memcpy(&vheader, vfieldtableptr, VFIELD_HEADER_SIZE); | ||
209 | |||
210 | if (vregheader.version != VBIOS_VFIELD_TABLE_VERSION_1_0) { | ||
211 | gk20a_err(dev_from_gk20a(g), "invalid vfield header version"); | ||
212 | goto done; | ||
213 | } | ||
214 | |||
215 | pvfevar->vfield_info.fuse.segment_count = 0; | ||
216 | pvfevar->vfield_ver_info.fuse.segment_count = 0; | ||
217 | for (i = 0; i < (u32)vheader.count; i++) { | ||
218 | memcpy(&ventry, vfieldtableptr + vfieldheadersize + | ||
219 | (i * vheader.entry_size), | ||
220 | vheader.entry_size); | ||
221 | |||
222 | currindex = VFIELD_BIT_REG(ventry); | ||
223 | if (currindex != oldindex) { | ||
224 | |||
225 | memcpy(&vregentry, vfieldregtableptr + | ||
226 | vfieldregheadersize + | ||
227 | (currindex * vregheader.entry_size), | ||
228 | vregheader.entry_size); | ||
229 | oldindex = currindex; | ||
230 | } | ||
231 | |||
232 | if (pvfevar->vfield_info.v_field_id == ventry.strap_id) { | ||
233 | psegmentcount = | ||
234 | &(pvfevar->vfield_info.fuse.segment_count); | ||
235 | psegment = | ||
236 | &(pvfevar->vfield_info.fuse.segments[*psegmentcount]); | ||
237 | if (*psegmentcount > NV_PMU_VFE_VAR_SINGLE_SENSED_FUSE_SEGMENTS_MAX) { | ||
238 | status = -EINVAL; | ||
239 | goto done; | ||
240 | } | ||
241 | } else if (pvfevar->vfield_ver_info.v_field_id_ver == ventry.strap_id) { | ||
242 | psegmentcount = | ||
243 | &(pvfevar->vfield_ver_info.fuse.segment_count); | ||
244 | psegment = | ||
245 | &(pvfevar->vfield_ver_info.fuse.segments[*psegmentcount]); | ||
246 | if (*psegmentcount > NV_PMU_VFE_VAR_SINGLE_SENSED_FUSE_SEGMENTS_MAX) { | ||
247 | status = -EINVAL; | ||
248 | goto done; | ||
249 | } | ||
250 | } else { | ||
251 | continue; | ||
252 | } | ||
253 | |||
254 | psegment->super.high_bit = (u8)(VFIELD_BIT_STOP(ventry)); | ||
255 | psegment->super.low_bit = (u8)(VFIELD_BIT_START(ventry)); | ||
256 | switch (VFIELD_CODE((&vregentry))) { | ||
257 | case NV_VFIELD_DESC_CODE_REG: | ||
258 | psegment->reg.super.type = | ||
259 | NV_PMU_BIOS_VFIELD_DESC_CODE_REG; | ||
260 | psegment->reg.addr = vregentry.reg; | ||
261 | break; | ||
262 | |||
263 | case NV_VFIELD_DESC_CODE_INDEX_REG: | ||
264 | psegment->index_reg.super.type = | ||
265 | NV_PMU_BIOS_VFIELD_DESC_CODE_INDEX_REG; | ||
266 | psegment->index_reg.addr = vregentry.reg; | ||
267 | psegment->index_reg.index = vregentry.index; | ||
268 | psegment->index_reg.reg_index = vregentry.reg_index; | ||
269 | break; | ||
270 | |||
271 | default: | ||
272 | psegment->super.type = | ||
273 | NV_PMU_BIOS_VFIELD_DESC_CODE_INVALID; | ||
274 | status = -EINVAL; | ||
275 | goto done; | ||
276 | } | ||
277 | |||
278 | if (VFIELD_SIZE((&vregentry)) != NV_VFIELD_DESC_SIZE_DWORD) { | ||
279 | psegment->super.type = | ||
280 | NV_PMU_BIOS_VFIELD_DESC_CODE_INVALID; | ||
281 | return -EINVAL; | ||
282 | } | ||
283 | (*psegmentcount)++; | ||
284 | } | ||
285 | |||
286 | done: | ||
287 | |||
288 | return status; | ||
289 | } | ||
290 | |||
291 | static u32 _vfe_var_pmudatainit_super(struct gk20a *g, | ||
292 | struct boardobj *board_obj_ptr, | ||
293 | struct nv_pmu_boardobj *ppmudata) | ||
294 | { | ||
295 | u32 status = 0; | ||
296 | struct vfe_var *pvfe_var; | ||
297 | struct nv_pmu_vfe_var *pset; | ||
298 | |||
299 | gk20a_dbg_info(""); | ||
300 | |||
301 | status = boardobj_pmudatainit_super(g, board_obj_ptr, ppmudata); | ||
302 | if (status != 0) | ||
303 | return status; | ||
304 | |||
305 | pvfe_var = (struct vfe_var *)board_obj_ptr; | ||
306 | pset = (struct nv_pmu_vfe_var *) ppmudata; | ||
307 | |||
308 | pset->out_range_min = pvfe_var->out_range_min; | ||
309 | pset->out_range_max = pvfe_var->out_range_max; | ||
310 | |||
311 | return status; | ||
312 | } | ||
313 | |||
314 | static u32 vfe_var_construct_super(struct gk20a *g, | ||
315 | struct boardobj **ppboardobj, | ||
316 | u16 size, void *pargs) | ||
317 | { | ||
318 | struct vfe_var *pvfevar; | ||
319 | struct vfe_var *ptmpvar = (struct vfe_var *)pargs; | ||
320 | u32 status = 0; | ||
321 | |||
322 | gk20a_dbg_info(""); | ||
323 | |||
324 | status = boardobj_construct_super(g, ppboardobj, size, pargs); | ||
325 | if (status) | ||
326 | return -EINVAL; | ||
327 | |||
328 | pvfevar = (struct vfe_var *)*ppboardobj; | ||
329 | |||
330 | pvfevar->super.pmudatainit = | ||
331 | _vfe_var_pmudatainit_super; | ||
332 | |||
333 | pvfevar->out_range_min = ptmpvar->out_range_min; | ||
334 | pvfevar->out_range_max = ptmpvar->out_range_max; | ||
335 | pvfevar->b_is_dynamic_valid = false; | ||
336 | |||
337 | gk20a_dbg_info(""); | ||
338 | |||
339 | return status; | ||
340 | } | ||
341 | |||
342 | static u32 _vfe_var_pmudatainit_derived(struct gk20a *g, | ||
343 | struct boardobj *board_obj_ptr, | ||
344 | struct nv_pmu_boardobj *ppmudata) | ||
345 | { | ||
346 | u32 status = 0; | ||
347 | |||
348 | gk20a_dbg_info(""); | ||
349 | |||
350 | status = _vfe_var_pmudatainit_super(g, board_obj_ptr, ppmudata); | ||
351 | |||
352 | return status; | ||
353 | } | ||
354 | |||
355 | static u32 vfe_var_construct_derived(struct gk20a *g, | ||
356 | struct boardobj **ppboardobj, | ||
357 | u16 size, void *pargs) | ||
358 | { | ||
359 | struct boardobj *ptmpobj = (struct boardobj *)pargs; | ||
360 | u32 status = 0; | ||
361 | struct vfe_var_derived *pvfevar; | ||
362 | |||
363 | ptmpobj->type_mask |= BIT(CTRL_PERF_VFE_VAR_TYPE_DERIVED); | ||
364 | status = vfe_var_construct_super(g, ppboardobj, size, pargs); | ||
365 | if (status) | ||
366 | return -EINVAL; | ||
367 | |||
368 | pvfevar = (struct vfe_var_derived *)*ppboardobj; | ||
369 | |||
370 | pvfevar->super.super.pmudatainit = | ||
371 | _vfe_var_pmudatainit_derived; | ||
372 | |||
373 | return status; | ||
374 | } | ||
375 | |||
376 | static u32 _vfe_var_pmudatainit_derived_product(struct gk20a *g, | ||
377 | struct boardobj *board_obj_ptr, | ||
378 | struct nv_pmu_boardobj *ppmudata) | ||
379 | { | ||
380 | u32 status = 0; | ||
381 | struct vfe_var_derived_product *pvfe_var_derived_product; | ||
382 | struct nv_pmu_vfe_var_derived_product *pset; | ||
383 | |||
384 | gk20a_dbg_info(""); | ||
385 | |||
386 | status = _vfe_var_pmudatainit_derived(g, board_obj_ptr, ppmudata); | ||
387 | if (status != 0) | ||
388 | return status; | ||
389 | |||
390 | pvfe_var_derived_product = | ||
391 | (struct vfe_var_derived_product *)board_obj_ptr; | ||
392 | pset = (struct nv_pmu_vfe_var_derived_product *)ppmudata; | ||
393 | |||
394 | pset->var_idx0 = pvfe_var_derived_product->var_idx0; | ||
395 | pset->var_idx1 = pvfe_var_derived_product->var_idx1; | ||
396 | |||
397 | return status; | ||
398 | } | ||
399 | |||
400 | static u32 vfe_var_construct_derived_product(struct gk20a *g, | ||
401 | struct boardobj **ppboardobj, | ||
402 | u16 size, void *pargs) | ||
403 | { | ||
404 | struct boardobj *ptmpobj = (struct boardobj *)pargs; | ||
405 | struct vfe_var_derived_product *pvfevar; | ||
406 | struct vfe_var_derived_product *ptmpvar = | ||
407 | (struct vfe_var_derived_product *)pargs; | ||
408 | u32 status = 0; | ||
409 | |||
410 | if (BOARDOBJ_GET_TYPE(pargs) != CTRL_PERF_VFE_VAR_TYPE_DERIVED_PRODUCT) | ||
411 | return -EINVAL; | ||
412 | |||
413 | ptmpobj->type_mask |= BIT(CTRL_PERF_VFE_VAR_TYPE_DERIVED_PRODUCT); | ||
414 | status = vfe_var_construct_derived(g, ppboardobj, size, pargs); | ||
415 | if (status) | ||
416 | return -EINVAL; | ||
417 | |||
418 | pvfevar = (struct vfe_var_derived_product *)*ppboardobj; | ||
419 | |||
420 | pvfevar->super.super.super.pmudatainit = | ||
421 | _vfe_var_pmudatainit_derived_product; | ||
422 | |||
423 | pvfevar->var_idx0 = ptmpvar->var_idx0; | ||
424 | pvfevar->var_idx1 = ptmpvar->var_idx1; | ||
425 | |||
426 | |||
427 | return status; | ||
428 | } | ||
429 | |||
430 | static u32 _vfe_var_pmudatainit_derived_sum(struct gk20a *g, | ||
431 | struct boardobj *board_obj_ptr, | ||
432 | struct nv_pmu_boardobj *ppmudata) | ||
433 | { | ||
434 | u32 status = 0; | ||
435 | struct vfe_var_derived_sum *pvfe_var_derived_sum; | ||
436 | struct nv_pmu_vfe_var_derived_sum *pset; | ||
437 | |||
438 | gk20a_dbg_info(""); | ||
439 | |||
440 | status = _vfe_var_pmudatainit_derived(g, board_obj_ptr, ppmudata); | ||
441 | if (status != 0) | ||
442 | return status; | ||
443 | |||
444 | pvfe_var_derived_sum = (struct vfe_var_derived_sum *)board_obj_ptr; | ||
445 | pset = (struct nv_pmu_vfe_var_derived_sum *)ppmudata; | ||
446 | |||
447 | pset->var_idx0 = pvfe_var_derived_sum->var_idx0; | ||
448 | pset->var_idx1 = pvfe_var_derived_sum->var_idx1; | ||
449 | |||
450 | return status; | ||
451 | } | ||
452 | |||
453 | static u32 vfe_var_construct_derived_sum(struct gk20a *g, | ||
454 | struct boardobj **ppboardobj, | ||
455 | u16 size, void *pargs) | ||
456 | { | ||
457 | struct boardobj *ptmpobj = (struct boardobj *)pargs; | ||
458 | struct vfe_var_derived_sum *pvfevar; | ||
459 | struct vfe_var_derived_sum *ptmpvar = | ||
460 | (struct vfe_var_derived_sum *)pargs; | ||
461 | u32 status = 0; | ||
462 | |||
463 | if (BOARDOBJ_GET_TYPE(pargs) != CTRL_PERF_VFE_VAR_TYPE_DERIVED_SUM) | ||
464 | return -EINVAL; | ||
465 | |||
466 | ptmpobj->type_mask |= BIT(CTRL_PERF_VFE_VAR_TYPE_DERIVED_SUM); | ||
467 | status = vfe_var_construct_derived(g, ppboardobj, size, pargs); | ||
468 | if (status) | ||
469 | return -EINVAL; | ||
470 | |||
471 | pvfevar = (struct vfe_var_derived_sum *)*ppboardobj; | ||
472 | |||
473 | pvfevar->super.super.super.pmudatainit = | ||
474 | _vfe_var_pmudatainit_derived_sum; | ||
475 | |||
476 | pvfevar->var_idx0 = ptmpvar->var_idx0; | ||
477 | pvfevar->var_idx1 = ptmpvar->var_idx1; | ||
478 | |||
479 | return status; | ||
480 | } | ||
481 | |||
482 | static u32 _vfe_var_pmudatainit_single(struct gk20a *g, | ||
483 | struct boardobj *board_obj_ptr, | ||
484 | struct nv_pmu_boardobj *ppmudata) | ||
485 | { | ||
486 | u32 status = 0; | ||
487 | struct vfe_var_single *pvfe_var_single; | ||
488 | struct nv_pmu_vfe_var_single *pset; | ||
489 | |||
490 | gk20a_dbg_info(""); | ||
491 | |||
492 | status = _vfe_var_pmudatainit_super(g, board_obj_ptr, ppmudata); | ||
493 | if (status != 0) | ||
494 | return status; | ||
495 | |||
496 | pvfe_var_single = (struct vfe_var_single *)board_obj_ptr; | ||
497 | pset = (struct nv_pmu_vfe_var_single *) | ||
498 | ppmudata; | ||
499 | |||
500 | pset->override_type = pvfe_var_single->override_type; | ||
501 | pset->override_value = pvfe_var_single->override_value; | ||
502 | |||
503 | return status; | ||
504 | } | ||
505 | |||
506 | static u32 _vfe_var_pmudatainit_single_frequency(struct gk20a *g, | ||
507 | struct boardobj *board_obj_ptr, | ||
508 | struct nv_pmu_boardobj *ppmudata) | ||
509 | { | ||
510 | u32 status = 0; | ||
511 | |||
512 | gk20a_dbg_info(""); | ||
513 | |||
514 | status = _vfe_var_pmudatainit_single(g, board_obj_ptr, ppmudata); | ||
515 | |||
516 | return status; | ||
517 | } | ||
518 | |||
519 | static u32 vfe_var_construct_single_frequency(struct gk20a *g, | ||
520 | struct boardobj **ppboardobj, | ||
521 | u16 size, void *pargs) | ||
522 | { | ||
523 | struct boardobj *ptmpobj = (struct boardobj *)pargs; | ||
524 | struct vfe_var_single_frequency *pvfevar; | ||
525 | u32 status = 0; | ||
526 | |||
527 | gk20a_dbg_info(""); | ||
528 | |||
529 | if (BOARDOBJ_GET_TYPE(pargs) != CTRL_PERF_VFE_VAR_TYPE_SINGLE_FREQUENCY) | ||
530 | return -EINVAL; | ||
531 | |||
532 | ptmpobj->type_mask |= BIT(CTRL_PERF_VFE_VAR_TYPE_SINGLE_FREQUENCY); | ||
533 | status = vfe_var_construct_single(g, ppboardobj, size, pargs); | ||
534 | if (status) | ||
535 | return -EINVAL; | ||
536 | |||
537 | pvfevar = (struct vfe_var_single_frequency *)*ppboardobj; | ||
538 | |||
539 | pvfevar->super.super.super.pmudatainit = | ||
540 | _vfe_var_pmudatainit_single_frequency; | ||
541 | |||
542 | pvfevar->super.super.b_is_dynamic = false; | ||
543 | pvfevar->super.super.b_is_dynamic_valid = true; | ||
544 | |||
545 | gk20a_dbg_info("Done"); | ||
546 | return status; | ||
547 | } | ||
548 | |||
549 | static u32 _vfe_var_pmudatainit_single_sensed(struct gk20a *g, | ||
550 | struct boardobj *board_obj_ptr, | ||
551 | struct nv_pmu_boardobj *ppmudata) | ||
552 | { | ||
553 | u32 status = 0; | ||
554 | |||
555 | gk20a_dbg_info(""); | ||
556 | |||
557 | status = _vfe_var_pmudatainit_single(g, board_obj_ptr, ppmudata); | ||
558 | |||
559 | return status; | ||
560 | } | ||
561 | |||
562 | static u32 _vfe_var_pmudatainit_single_sensed_fuse(struct gk20a *g, | ||
563 | struct boardobj *board_obj_ptr, | ||
564 | struct nv_pmu_boardobj *ppmudata) | ||
565 | { | ||
566 | u32 status = 0; | ||
567 | struct vfe_var_single_sensed_fuse *pvfe_var_single_sensed_fuse; | ||
568 | struct nv_pmu_vfe_var_single_sensed_fuse *pset; | ||
569 | |||
570 | gk20a_dbg_info(""); | ||
571 | |||
572 | status = _vfe_var_pmudatainit_single_sensed(g, board_obj_ptr, ppmudata); | ||
573 | if (status != 0) | ||
574 | return status; | ||
575 | |||
576 | pvfe_var_single_sensed_fuse = | ||
577 | (struct vfe_var_single_sensed_fuse *)board_obj_ptr; | ||
578 | |||
579 | pset = (struct nv_pmu_vfe_var_single_sensed_fuse *) | ||
580 | ppmudata; | ||
581 | |||
582 | memcpy(&pset->vfield_info, &pvfe_var_single_sensed_fuse->vfield_info, | ||
583 | sizeof(struct nv_pmu_vfe_var_single_sensed_fuse_vfield_info)); | ||
584 | |||
585 | memcpy(&pset->vfield_ver_info, | ||
586 | &pvfe_var_single_sensed_fuse->vfield_ver_info, | ||
587 | sizeof(struct nv_pmu_vfe_var_single_sensed_fuse_ver_vfield_info)); | ||
588 | |||
589 | memcpy(&pset->override_info, | ||
590 | &pvfe_var_single_sensed_fuse->override_info, | ||
591 | sizeof(struct nv_pmu_vfe_var_single_sensed_fuse_override_info)); | ||
592 | |||
593 | return status; | ||
594 | } | ||
595 | |||
596 | static u32 vfe_var_construct_single_sensed(struct gk20a *g, | ||
597 | struct boardobj **ppboardobj, | ||
598 | u16 size, void *pargs) | ||
599 | { | ||
600 | struct boardobj *ptmpobj = (struct boardobj *)pargs; | ||
601 | struct vfe_var_single_sensed *pvfevar; | ||
602 | |||
603 | u32 status = 0; | ||
604 | |||
605 | gk20a_dbg_info(" "); | ||
606 | |||
607 | ptmpobj->type_mask |= BIT(CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED); | ||
608 | status = vfe_var_construct_single(g, ppboardobj, size, pargs); | ||
609 | if (status) | ||
610 | return -EINVAL; | ||
611 | |||
612 | pvfevar = (struct vfe_var_single_sensed *)*ppboardobj; | ||
613 | |||
614 | pvfevar->super.super.super.pmudatainit = | ||
615 | _vfe_var_pmudatainit_single_sensed; | ||
616 | |||
617 | gk20a_dbg_info("Done"); | ||
618 | |||
619 | return status; | ||
620 | } | ||
621 | |||
622 | static u32 vfe_var_construct_single_sensed_fuse(struct gk20a *g, | ||
623 | struct boardobj **ppboardobj, | ||
624 | u16 size, void *pargs) | ||
625 | { | ||
626 | struct boardobj *ptmpobj = (struct boardobj *)pargs; | ||
627 | struct vfe_var_single_sensed_fuse *pvfevar; | ||
628 | struct vfe_var_single_sensed_fuse *ptmpvar = | ||
629 | (struct vfe_var_single_sensed_fuse *)pargs; | ||
630 | u32 status = 0; | ||
631 | |||
632 | gk20a_dbg_info(""); | ||
633 | |||
634 | if (BOARDOBJ_GET_TYPE(pargs) != CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED_FUSE) | ||
635 | return -EINVAL; | ||
636 | |||
637 | ptmpobj->type_mask |= BIT(CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED_FUSE); | ||
638 | status = vfe_var_construct_single_sensed(g, ppboardobj, size, pargs); | ||
639 | if (status) | ||
640 | return -EINVAL; | ||
641 | |||
642 | pvfevar = (struct vfe_var_single_sensed_fuse *)*ppboardobj; | ||
643 | |||
644 | pvfevar->super.super.super.super.pmudatainit = | ||
645 | _vfe_var_pmudatainit_single_sensed_fuse; | ||
646 | |||
647 | pvfevar->vfield_info.v_field_id = ptmpvar->vfield_info.v_field_id; | ||
648 | pvfevar->vfield_info.fuse_val_default = | ||
649 | ptmpvar->vfield_info.fuse_val_default; | ||
650 | pvfevar->vfield_info.hw_correction_scale = | ||
651 | ptmpvar->vfield_info.hw_correction_scale; | ||
652 | pvfevar->vfield_info.hw_correction_offset = | ||
653 | ptmpvar->vfield_info.hw_correction_offset; | ||
654 | pvfevar->vfield_ver_info.v_field_id_ver = | ||
655 | ptmpvar->vfield_ver_info.v_field_id_ver; | ||
656 | pvfevar->vfield_ver_info.ver_expected = | ||
657 | ptmpvar->vfield_ver_info.ver_expected; | ||
658 | pvfevar->vfield_ver_info.b_use_default_on_ver_check_fail = | ||
659 | ptmpvar->vfield_ver_info.b_use_default_on_ver_check_fail; | ||
660 | pvfevar->b_version_check_done = false; | ||
661 | |||
662 | pvfevar->super.super.super.b_is_dynamic = false; | ||
663 | pvfevar->super.super.super.b_is_dynamic_valid = true; | ||
664 | |||
665 | dev_init_get_vfield_info(g, pvfevar); | ||
666 | /*check whether fuse segment got initialized*/ | ||
667 | if (pvfevar->vfield_info.fuse.segment_count == 0) { | ||
668 | gk20a_err(dev_from_gk20a(g), "unable to get fuse reg info %x", | ||
669 | pvfevar->vfield_info.v_field_id); | ||
670 | return -EINVAL; | ||
671 | } | ||
672 | if (pvfevar->vfield_ver_info.fuse.segment_count == 0) { | ||
673 | gk20a_err(dev_from_gk20a(g), "unable to get fuse reg info %x", | ||
674 | pvfevar->vfield_ver_info.v_field_id_ver); | ||
675 | return -EINVAL; | ||
676 | } | ||
677 | return status; | ||
678 | } | ||
679 | |||
680 | static u32 _vfe_var_pmudatainit_single_sensed_temp(struct gk20a *g, | ||
681 | struct boardobj *board_obj_ptr, | ||
682 | struct nv_pmu_boardobj *ppmudata) | ||
683 | { | ||
684 | u32 status = 0; | ||
685 | struct vfe_var_single_sensed_temp *pvfe_var_single_sensed_temp; | ||
686 | struct nv_pmu_vfe_var_single_sensed_temp *pset; | ||
687 | |||
688 | gk20a_dbg_info(""); | ||
689 | |||
690 | status = _vfe_var_pmudatainit_single_sensed(g, board_obj_ptr, ppmudata); | ||
691 | if (status != 0) | ||
692 | return status; | ||
693 | |||
694 | pvfe_var_single_sensed_temp = | ||
695 | (struct vfe_var_single_sensed_temp *)board_obj_ptr; | ||
696 | |||
697 | pset = (struct nv_pmu_vfe_var_single_sensed_temp *) | ||
698 | ppmudata; | ||
699 | pset->therm_channel_index = | ||
700 | pvfe_var_single_sensed_temp->therm_channel_index; | ||
701 | pset->temp_hysteresis_positive = | ||
702 | pvfe_var_single_sensed_temp->temp_hysteresis_positive; | ||
703 | pset->temp_hysteresis_negative = | ||
704 | pvfe_var_single_sensed_temp->temp_hysteresis_negative; | ||
705 | pset->temp_default = | ||
706 | pvfe_var_single_sensed_temp->temp_default; | ||
707 | return status; | ||
708 | } | ||
709 | |||
710 | static u32 vfe_var_construct_single_sensed_temp(struct gk20a *g, | ||
711 | struct boardobj **ppboardobj, | ||
712 | u16 size, void *pargs) | ||
713 | { | ||
714 | struct boardobj *ptmpobj = (struct boardobj *)pargs; | ||
715 | struct vfe_var_single_sensed_temp *pvfevar; | ||
716 | struct vfe_var_single_sensed_temp *ptmpvar = | ||
717 | (struct vfe_var_single_sensed_temp *)pargs; | ||
718 | u32 status = 0; | ||
719 | |||
720 | if (BOARDOBJ_GET_TYPE(pargs) != CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED_TEMP) | ||
721 | return -EINVAL; | ||
722 | |||
723 | ptmpobj->type_mask |= BIT(CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED_TEMP); | ||
724 | status = vfe_var_construct_single_sensed(g, ppboardobj, size, pargs); | ||
725 | if (status) | ||
726 | return -EINVAL; | ||
727 | |||
728 | pvfevar = (struct vfe_var_single_sensed_temp *)*ppboardobj; | ||
729 | |||
730 | pvfevar->super.super.super.super.pmudatainit = | ||
731 | _vfe_var_pmudatainit_single_sensed_temp; | ||
732 | |||
733 | pvfevar->therm_channel_index = | ||
734 | ptmpvar->therm_channel_index; | ||
735 | pvfevar->temp_hysteresis_positive = | ||
736 | ptmpvar->temp_hysteresis_positive; | ||
737 | pvfevar->temp_hysteresis_negative = | ||
738 | ptmpvar->temp_hysteresis_negative; | ||
739 | pvfevar->temp_default = | ||
740 | ptmpvar->temp_default; | ||
741 | pvfevar->super.super.super.b_is_dynamic = false; | ||
742 | pvfevar->super.super.super.b_is_dynamic_valid = true; | ||
743 | |||
744 | return status; | ||
745 | } | ||
746 | |||
747 | static u32 _vfe_var_pmudatainit_single_voltage(struct gk20a *g, | ||
748 | struct boardobj *board_obj_ptr, | ||
749 | struct nv_pmu_boardobj *ppmudata) | ||
750 | { | ||
751 | u32 status = 0; | ||
752 | |||
753 | gk20a_dbg_info(""); | ||
754 | |||
755 | status = _vfe_var_pmudatainit_single(g, board_obj_ptr, ppmudata); | ||
756 | |||
757 | return status; | ||
758 | } | ||
759 | |||
760 | static u32 vfe_var_construct_single_voltage(struct gk20a *g, | ||
761 | struct boardobj **ppboardobj, | ||
762 | u16 size, void *pargs) | ||
763 | { | ||
764 | struct boardobj *ptmpobj = (struct boardobj *)pargs; | ||
765 | struct vfe_var_single_voltage *pvfevar; | ||
766 | u32 status = 0; | ||
767 | |||
768 | if (BOARDOBJ_GET_TYPE(pargs) != CTRL_PERF_VFE_VAR_TYPE_SINGLE_VOLTAGE) | ||
769 | return -EINVAL; | ||
770 | |||
771 | ptmpobj->type_mask |= BIT(CTRL_PERF_VFE_VAR_TYPE_SINGLE_VOLTAGE); | ||
772 | status = vfe_var_construct_super(g, ppboardobj, size, pargs); | ||
773 | if (status) | ||
774 | return -EINVAL; | ||
775 | |||
776 | pvfevar = (struct vfe_var_single_voltage *)*ppboardobj; | ||
777 | |||
778 | pvfevar->super.super.super.pmudatainit = | ||
779 | _vfe_var_pmudatainit_single_voltage; | ||
780 | |||
781 | pvfevar->super.super.b_is_dynamic = false; | ||
782 | pvfevar->super.super.b_is_dynamic_valid = true; | ||
783 | |||
784 | return status; | ||
785 | } | ||
786 | |||
787 | static struct vfe_var *construct_vfe_var(struct gk20a *g, void *pargs) | ||
788 | { | ||
789 | struct boardobj *board_obj_ptr = NULL; | ||
790 | u32 status; | ||
791 | |||
792 | gk20a_dbg_info(""); | ||
793 | switch (BOARDOBJ_GET_TYPE(pargs)) { | ||
794 | case CTRL_PERF_VFE_VAR_TYPE_DERIVED_PRODUCT: | ||
795 | status = vfe_var_construct_derived_product(g, &board_obj_ptr, | ||
796 | sizeof(struct vfe_var_derived_product), pargs); | ||
797 | break; | ||
798 | |||
799 | case CTRL_PERF_VFE_VAR_TYPE_DERIVED_SUM: | ||
800 | status = vfe_var_construct_derived_sum(g, &board_obj_ptr, | ||
801 | sizeof(struct vfe_var_derived_sum), pargs); | ||
802 | break; | ||
803 | |||
804 | case CTRL_PERF_VFE_VAR_TYPE_SINGLE_FREQUENCY: | ||
805 | status = vfe_var_construct_single_frequency(g, &board_obj_ptr, | ||
806 | sizeof(struct vfe_var_single_frequency), pargs); | ||
807 | break; | ||
808 | |||
809 | case CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED_FUSE: | ||
810 | status = vfe_var_construct_single_sensed_fuse(g, &board_obj_ptr, | ||
811 | sizeof(struct vfe_var_single_sensed_fuse), pargs); | ||
812 | break; | ||
813 | |||
814 | case CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED_TEMP: | ||
815 | status = vfe_var_construct_single_sensed_temp(g, &board_obj_ptr, | ||
816 | sizeof(struct vfe_var_single_sensed_temp), pargs); | ||
817 | break; | ||
818 | |||
819 | case CTRL_PERF_VFE_VAR_TYPE_SINGLE_VOLTAGE: | ||
820 | status = vfe_var_construct_single_voltage(g, &board_obj_ptr, | ||
821 | sizeof(struct vfe_var_single_voltage), pargs); | ||
822 | break; | ||
823 | |||
824 | case CTRL_PERF_VFE_VAR_TYPE_DERIVED: | ||
825 | case CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED: | ||
826 | case CTRL_PERF_VFE_VAR_TYPE_SINGLE: | ||
827 | default: | ||
828 | return NULL; | ||
829 | } | ||
830 | |||
831 | if (status) | ||
832 | return NULL; | ||
833 | |||
834 | gk20a_dbg_info("done"); | ||
835 | |||
836 | return (struct vfe_var *)board_obj_ptr; | ||
837 | } | ||
838 | |||
839 | static u32 devinit_get_vfe_var_table(struct gk20a *g, | ||
840 | struct vfe_vars *pvfevarobjs) | ||
841 | { | ||
842 | u32 status = 0; | ||
843 | u8 *vfevars_tbl_ptr = NULL; | ||
844 | struct vbios_vfe_3x_header_struct vfevars_tbl_header = { 0 }; | ||
845 | struct vbios_vfe_3x_var_entry_struct var = { 0 }; | ||
846 | u8 *vfevars_tbl_entry_ptr = NULL; | ||
847 | u8 *rd_offset_ptr = NULL; | ||
848 | u32 index = 0; | ||
849 | struct vfe_var *pvar; | ||
850 | u8 var_type; | ||
851 | u32 szfmt; | ||
852 | union { | ||
853 | struct boardobj board_obj; | ||
854 | struct vfe_var super; | ||
855 | struct vfe_var_derived_product derived_product; | ||
856 | struct vfe_var_derived_sum derived_sum; | ||
857 | struct vfe_var_single_sensed_fuse single_sensed_fuse; | ||
858 | struct vfe_var_single_sensed_temp single_sensed_temp; | ||
859 | } var_data; | ||
860 | |||
861 | gk20a_dbg_info(""); | ||
862 | |||
863 | if (g->ops.bios.get_perf_table_ptrs) { | ||
864 | vfevars_tbl_ptr = (u8 *)g->ops.bios.get_perf_table_ptrs(g, | ||
865 | g->bios.perf_token, | ||
866 | CONTINUOUS_VIRTUAL_BINNING_TABLE); | ||
867 | if (vfevars_tbl_ptr == NULL) { | ||
868 | status = -EINVAL; | ||
869 | goto done; | ||
870 | } | ||
871 | } | ||
872 | |||
873 | memcpy(&vfevars_tbl_header, vfevars_tbl_ptr, | ||
874 | VBIOS_CLOCKS_TABLE_1X_HEADER_SIZE_07); | ||
875 | if (vfevars_tbl_header.header_size != | ||
876 | VBIOS_CLOCKS_TABLE_1X_HEADER_SIZE_07){ | ||
877 | status = -EINVAL; | ||
878 | goto done; | ||
879 | } | ||
880 | |||
881 | if (vfevars_tbl_header.vfe_var_entry_size == | ||
882 | VBIOS_VFE_3X_VAR_ENTRY_SIZE_19) | ||
883 | szfmt = VBIOS_VFE_3X_VAR_ENTRY_SIZE_19; | ||
884 | else if (vfevars_tbl_header.vfe_var_entry_size == | ||
885 | VBIOS_VFE_3X_VAR_ENTRY_SIZE_11) | ||
886 | szfmt = VBIOS_VFE_3X_VAR_ENTRY_SIZE_11; | ||
887 | else { | ||
888 | status = -EINVAL; | ||
889 | goto done; | ||
890 | } | ||
891 | |||
892 | /* Read table entries*/ | ||
893 | vfevars_tbl_entry_ptr = vfevars_tbl_ptr + | ||
894 | vfevars_tbl_header.header_size; | ||
895 | |||
896 | for (index = 0; | ||
897 | index < vfevars_tbl_header.vfe_var_entry_count; | ||
898 | index++) { | ||
899 | rd_offset_ptr = vfevars_tbl_entry_ptr + | ||
900 | (index * vfevars_tbl_header.vfe_var_entry_size); | ||
901 | memcpy(&var, rd_offset_ptr, szfmt); | ||
902 | |||
903 | var_data.super.out_range_min = var.out_range_min; | ||
904 | var_data.super.out_range_max = var.out_range_max; | ||
905 | |||
906 | var_data.super.out_range_min = var.out_range_min; | ||
907 | var_data.super.out_range_max = var.out_range_max; | ||
908 | |||
909 | switch ((u8)var.type) { | ||
910 | case VBIOS_VFE_3X_VAR_ENTRY_TYPE_DISABLED: | ||
911 | continue; | ||
912 | break; | ||
913 | |||
914 | case VBIOS_VFE_3X_VAR_ENTRY_TYPE_SINGLE_FREQUENCY: | ||
915 | var_type = CTRL_PERF_VFE_VAR_TYPE_SINGLE_FREQUENCY; | ||
916 | break; | ||
917 | |||
918 | case VBIOS_VFE_3X_VAR_ENTRY_TYPE_SINGLE_VOLTAGE: | ||
919 | var_type = CTRL_PERF_VFE_VAR_TYPE_SINGLE_VOLTAGE; | ||
920 | break; | ||
921 | |||
922 | case VBIOS_VFE_3X_VAR_ENTRY_TYPE_SINGLE_SENSED_TEMP: | ||
923 | var_type = CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED_TEMP; | ||
924 | var_data.single_sensed_temp.temp_default = 0x9600; | ||
925 | var_data.single_sensed_temp.therm_channel_index = | ||
926 | (u8)BIOS_GET_FIELD(var.param0, | ||
927 | VBIOS_VFE_3X_VAR_ENTRY_PAR0_SSTEMP_TH_CH_IDX); | ||
928 | var_data.single_sensed_temp.temp_hysteresis_positive = | ||
929 | (u8)BIOS_GET_FIELD(var.param0, | ||
930 | VBIOS_VFE_3X_VAR_ENTRY_PAR0_SSTEMP_HYS_POS) << 5; | ||
931 | var_data.single_sensed_temp.temp_hysteresis_negative = | ||
932 | (u8)BIOS_GET_FIELD(var.param0, | ||
933 | VBIOS_VFE_3X_VAR_ENTRY_PAR0_SSTEMP_HYS_NEG) << 5; | ||
934 | break; | ||
935 | |||
936 | case VBIOS_VFE_3X_VAR_ENTRY_TYPE_SINGLE_SENSED_FUSE: | ||
937 | var_type = CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED_FUSE; | ||
938 | var_data.single_sensed_fuse.vfield_info.v_field_id = | ||
939 | (u8)BIOS_GET_FIELD(var.param0, | ||
940 | VBIOS_VFE_3X_VAR_ENTRY_PAR0_SSFUSE_VFIELD_ID); | ||
941 | var_data.single_sensed_fuse.vfield_ver_info.v_field_id_ver = | ||
942 | (u8)BIOS_GET_FIELD(var.param0, | ||
943 | VBIOS_VFE_3X_VAR_ENTRY_PAR0_SSFUSE_VFIELD_ID_VER); | ||
944 | var_data.single_sensed_fuse.vfield_ver_info.ver_expected = | ||
945 | (u8)BIOS_GET_FIELD(var.param0, | ||
946 | VBIOS_VFE_3X_VAR_ENTRY_PAR0_SSFUSE_EXPECTED_VER); | ||
947 | var_data.single_sensed_fuse.vfield_ver_info.b_use_default_on_ver_check_fail = | ||
948 | (BIOS_GET_FIELD(var.param0, | ||
949 | VBIOS_VFE_3X_VAR_ENTRY_PAR0_SSFUSE_USE_DEFAULT_ON_VER_CHECK_FAIL) && | ||
950 | VBIOS_VFE_3X_VAR_ENTRY_PAR0_SSFUSE_USE_DEFAULT_ON_VER_CHECK_FAIL_YES); | ||
951 | var_data.single_sensed_fuse.vfield_info.fuse_val_default = | ||
952 | var.param1; | ||
953 | if (szfmt >= VBIOS_VFE_3X_VAR_ENTRY_SIZE_19) { | ||
954 | var_data.single_sensed_fuse.vfield_info.hw_correction_scale = | ||
955 | (int)var.param2; | ||
956 | var_data.single_sensed_fuse.vfield_info.hw_correction_offset = | ||
957 | var.param3; | ||
958 | } else { | ||
959 | var_data.single_sensed_fuse.vfield_info.hw_correction_scale = | ||
960 | 1 << 12; | ||
961 | var_data.single_sensed_fuse.vfield_info.hw_correction_offset = | ||
962 | 0; | ||
963 | if ((var_data.single_sensed_fuse.vfield_info.v_field_id == | ||
964 | VFIELD_ID_STRAP_IDDQ) || | ||
965 | (var_data.single_sensed_fuse.vfield_info.v_field_id == | ||
966 | VFIELD_ID_STRAP_IDDQ_1)) { | ||
967 | var_data.single_sensed_fuse.vfield_info.hw_correction_scale = | ||
968 | 50 << 12; | ||
969 | } | ||
970 | } | ||
971 | break; | ||
972 | |||
973 | case VBIOS_VFE_3X_VAR_ENTRY_TYPE_DERIVED_PRODUCT: | ||
974 | var_type = CTRL_PERF_VFE_VAR_TYPE_DERIVED_PRODUCT; | ||
975 | var_data.derived_product.var_idx0 = | ||
976 | (u8)BIOS_GET_FIELD(var.param0, | ||
977 | VBIOS_VFE_3X_VAR_ENTRY_PAR0_DPROD_VFE_VAR_IDX_0); | ||
978 | var_data.derived_product.var_idx1 = | ||
979 | (u8)BIOS_GET_FIELD(var.param0, | ||
980 | VBIOS_VFE_3X_VAR_ENTRY_PAR0_DPROD_VFE_VAR_IDX_1); | ||
981 | break; | ||
982 | |||
983 | case VBIOS_VFE_3X_VAR_ENTRY_TYPE_DERIVED_SUM: | ||
984 | var_type = CTRL_PERF_VFE_VAR_TYPE_DERIVED_SUM; | ||
985 | var_data.derived_sum.var_idx0 = | ||
986 | (u8)BIOS_GET_FIELD(var.param0, | ||
987 | VBIOS_VFE_3X_VAR_ENTRY_PAR0_DSUM_VFE_VAR_IDX_0); | ||
988 | var_data.derived_sum.var_idx1 = | ||
989 | (u8)BIOS_GET_FIELD(var.param0, | ||
990 | VBIOS_VFE_3X_VAR_ENTRY_PAR0_DSUM_VFE_VAR_IDX_1); | ||
991 | break; | ||
992 | default: | ||
993 | status = -EINVAL; | ||
994 | goto done; | ||
995 | } | ||
996 | var_data.board_obj.type = var_type; | ||
997 | var_data.board_obj.type_mask = 0; | ||
998 | |||
999 | pvar = construct_vfe_var(g, &var_data); | ||
1000 | if (pvar == NULL) { | ||
1001 | gk20a_err(dev_from_gk20a(g), | ||
1002 | "error constructing vfe_var boardobj %d", | ||
1003 | index); | ||
1004 | status = -EINVAL; | ||
1005 | goto done; | ||
1006 | } | ||
1007 | |||
1008 | status = boardobjgrp_objinsert(&pvfevarobjs->super.super, | ||
1009 | (struct boardobj *)pvar, index); | ||
1010 | if (status) { | ||
1011 | gk20a_err(dev_from_gk20a(g), | ||
1012 | "error adding vfe_var boardobj %d", index); | ||
1013 | status = -EINVAL; | ||
1014 | goto done; | ||
1015 | } | ||
1016 | } | ||
1017 | pvfevarobjs->polling_periodms = vfevars_tbl_header.polling_periodms; | ||
1018 | done: | ||
1019 | gk20a_dbg_info("done status %x", status); | ||
1020 | return status; | ||
1021 | } | ||
1022 | |||
1023 | static u32 vfe_var_construct_single(struct gk20a *g, | ||
1024 | struct boardobj **ppboardobj, | ||
1025 | u16 size, void *pargs) | ||
1026 | { | ||
1027 | struct boardobj *ptmpobj = (struct boardobj *)pargs; | ||
1028 | struct vfe_var_single *pvfevar; | ||
1029 | u32 status = 0; | ||
1030 | |||
1031 | gk20a_dbg_info(""); | ||
1032 | |||
1033 | ptmpobj->type_mask |= BIT(CTRL_PERF_VFE_VAR_TYPE_SINGLE); | ||
1034 | status = vfe_var_construct_super(g, ppboardobj, size, pargs); | ||
1035 | if (status) | ||
1036 | return -EINVAL; | ||
1037 | |||
1038 | pvfevar = (struct vfe_var_single *)*ppboardobj; | ||
1039 | |||
1040 | pvfevar->super.super.pmudatainit = | ||
1041 | _vfe_var_pmudatainit_single; | ||
1042 | |||
1043 | pvfevar->override_type = CTRL_PERF_VFE_VAR_SINGLE_OVERRIDE_TYPE_NONE; | ||
1044 | pvfevar->override_value = 0; | ||
1045 | |||
1046 | gk20a_dbg_info("Done"); | ||
1047 | return status; | ||
1048 | } | ||
diff --git a/drivers/gpu/nvgpu/perf/vfe_var.h b/drivers/gpu/nvgpu/perf/vfe_var.h new file mode 100644 index 00000000..fc43311b --- /dev/null +++ b/drivers/gpu/nvgpu/perf/vfe_var.h | |||
@@ -0,0 +1,97 @@ | |||
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 | #ifndef _VFE_VAR_H_ | ||
15 | #define _VFE_VAR_H_ | ||
16 | |||
17 | #include "boardobj/boardobjgrp.h" | ||
18 | #include "pmuif/gpmuifperf.h" | ||
19 | #include "pmuif/gpmuifperfvfe.h" | ||
20 | |||
21 | u32 vfe_var_sw_setup(struct gk20a *g); | ||
22 | u32 vfe_var_pmu_setup(struct gk20a *g); | ||
23 | |||
24 | #define VFE_VAR_GET(_pperf, _idx) \ | ||
25 | ((struct vfe_var)BOARDOBJGRP_OBJ_GET_BY_IDX( \ | ||
26 | &((_pperf)->vfe.vars.super.super), (_idx))) | ||
27 | |||
28 | #define VFE_VAR_IDX_IS_VALID(_pperf, _idx) \ | ||
29 | boardobjgrp_idxisvalid(&((_pperf)->vfe.vars.super.super), (_idx)) | ||
30 | |||
31 | struct vfe_var { | ||
32 | struct boardobj super; | ||
33 | u32 out_range_min; | ||
34 | u32 out_range_max; | ||
35 | bool b_is_dynamic_valid; | ||
36 | bool b_is_dynamic; | ||
37 | }; | ||
38 | |||
39 | struct vfe_vars { | ||
40 | struct boardobjgrp_e32 super; | ||
41 | u8 polling_periodms; | ||
42 | }; | ||
43 | |||
44 | struct vfe_var_derived { | ||
45 | struct vfe_var super; | ||
46 | }; | ||
47 | |||
48 | struct vfe_var_derived_product { | ||
49 | struct vfe_var_derived super; | ||
50 | u8 var_idx0; | ||
51 | u8 var_idx1; | ||
52 | }; | ||
53 | |||
54 | struct vfe_var_derived_sum { | ||
55 | struct vfe_var_derived super; | ||
56 | u8 var_idx0; | ||
57 | u8 var_idx1; | ||
58 | }; | ||
59 | |||
60 | struct vfe_var_single { | ||
61 | struct vfe_var super; | ||
62 | u8 override_type; | ||
63 | u32 override_value; | ||
64 | }; | ||
65 | |||
66 | struct vfe_var_single_frequency { | ||
67 | struct vfe_var_single super; | ||
68 | }; | ||
69 | |||
70 | struct vfe_var_single_voltage { | ||
71 | struct vfe_var_single super; | ||
72 | }; | ||
73 | |||
74 | struct vfe_var_single_sensed { | ||
75 | struct vfe_var_single super; | ||
76 | }; | ||
77 | |||
78 | struct vfe_var_single_sensed_fuse { | ||
79 | struct vfe_var_single_sensed super; | ||
80 | struct nv_pmu_vfe_var_single_sensed_fuse_override_info override_info; | ||
81 | struct nv_pmu_vfe_var_single_sensed_fuse_vfield_info vfield_info; | ||
82 | struct nv_pmu_vfe_var_single_sensed_fuse_ver_vfield_info vfield_ver_info; | ||
83 | u32 fuse_value_integer; | ||
84 | u32 fuse_value_hw_integer; | ||
85 | u8 fuse_version; | ||
86 | bool b_version_check_done; | ||
87 | }; | ||
88 | |||
89 | struct vfe_var_single_sensed_temp { | ||
90 | struct vfe_var_single_sensed super; | ||
91 | u8 therm_channel_index; | ||
92 | int temp_hysteresis_positive; | ||
93 | int temp_hysteresis_negative; | ||
94 | int temp_default; | ||
95 | }; | ||
96 | |||
97 | #endif | ||