summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/volt/volt_pmu.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/nvgpu/volt/volt_pmu.c')
-rw-r--r--drivers/gpu/nvgpu/volt/volt_pmu.c243
1 files changed, 243 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/volt/volt_pmu.c b/drivers/gpu/nvgpu/volt/volt_pmu.c
new file mode 100644
index 00000000..4d451b65
--- /dev/null
+++ b/drivers/gpu/nvgpu/volt/volt_pmu.c
@@ -0,0 +1,243 @@
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 "ctrl/ctrlperf.h"
22#include "gk20a/pmu_gk20a.h"
23
24#include "pmuif/gpmuifperfvfe.h"
25#include "pmuif/gpmuifvolt.h"
26#include "include/bios.h"
27#include "volt.h"
28
29#define RAIL_COUNT 2
30
31struct volt_rpc_pmucmdhandler_params {
32 struct nv_pmu_volt_rpc *prpc_call;
33 u32 success;
34};
35
36static void volt_rpc_pmucmdhandler(struct gk20a *g, struct pmu_msg *msg,
37 void *param, u32 handle, u32 status)
38{
39 struct volt_rpc_pmucmdhandler_params *phandlerparams =
40 (struct volt_rpc_pmucmdhandler_params *)param;
41
42 gk20a_dbg_info("");
43
44 if (msg->msg.volt.msg_type != NV_PMU_VOLT_MSG_ID_RPC) {
45 gk20a_err(dev_from_gk20a(g), "unsupported msg for VOLT RPC %x",
46 msg->msg.volt.msg_type);
47 return;
48 }
49
50 if (phandlerparams->prpc_call->b_supported)
51 phandlerparams->success = 1;
52}
53
54
55static u32 volt_pmu_rpc_execute(struct gk20a *g,
56 struct nv_pmu_volt_rpc *prpc_call)
57{
58 struct pmu_cmd cmd = { { 0 } };
59 struct pmu_msg msg = { { 0 } };
60 struct pmu_payload payload = { { 0 } };
61 u32 status = 0;
62 u32 seqdesc;
63 struct volt_rpc_pmucmdhandler_params handler = {0};
64
65 cmd.hdr.unit_id = PMU_UNIT_VOLT;
66 cmd.hdr.size = (u32)sizeof(struct nv_pmu_volt_cmd) +
67 (u32)sizeof(struct pmu_hdr);
68 cmd.cmd.volt.cmd_type = NV_PMU_VOLT_CMD_ID_RPC;
69 msg.hdr.size = sizeof(struct pmu_msg);
70
71 payload.in.buf = (u8 *)prpc_call;
72 payload.in.size = (u32)sizeof(struct nv_pmu_volt_rpc);
73 payload.in.fb_size = PMU_CMD_SUBMIT_PAYLOAD_PARAMS_FB_SIZE_UNUSED;
74 payload.in.offset = NV_PMU_VOLT_CMD_RPC_ALLOC_OFFSET;
75
76 payload.out.buf = (u8 *)prpc_call;
77 payload.out.size = (u32)sizeof(struct nv_pmu_volt_rpc);
78 payload.out.fb_size = PMU_CMD_SUBMIT_PAYLOAD_PARAMS_FB_SIZE_UNUSED;
79 payload.out.offset = NV_PMU_VOLT_MSG_RPC_ALLOC_OFFSET;
80
81 handler.prpc_call = prpc_call;
82 handler.success = 0;
83
84 status = gk20a_pmu_cmd_post(g, &cmd, NULL, &payload,
85 PMU_COMMAND_QUEUE_LPQ,
86 volt_rpc_pmucmdhandler, (void *)&handler,
87 &seqdesc, ~0);
88 if (status) {
89 gk20a_err(dev_from_gk20a(g), "unable to post volt RPC cmd %x",
90 cmd.cmd.volt.cmd_type);
91 goto volt_pmu_rpc_execute;
92 }
93
94 pmu_wait_message_cond(&g->pmu,
95 gk20a_get_gr_idle_timeout(g),
96 &handler.success, 1);
97
98 if (handler.success == 0) {
99 status = -EINVAL;
100 gk20a_err(dev_from_gk20a(g), "rpc call to volt failed");
101 }
102
103volt_pmu_rpc_execute:
104 return status;
105}
106
107u32 volt_pmu_send_load_cmd_to_pmu(struct gk20a *g)
108{
109 struct nv_pmu_volt_rpc rpc_call = { 0 };
110 u32 status = 0;
111
112 rpc_call.function = NV_PMU_VOLT_RPC_ID_LOAD;
113
114 status = volt_pmu_rpc_execute(g, &rpc_call);
115 if (status)
116 gk20a_err(dev_from_gk20a(g),
117 "Error while executing LOAD RPC: status = 0x%08x.",
118 status);
119
120 return status;
121}
122
123static u32 volt_rail_get_voltage(struct gk20a *g,
124 u8 volt_domain, u32 *pvoltage_uv)
125{
126 struct nv_pmu_volt_rpc rpc_call = { 0 };
127 u32 status = 0;
128 u8 rail_idx;
129
130 rail_idx = volt_rail_volt_domain_convert_to_idx(g, volt_domain);
131 if ((rail_idx == CTRL_VOLT_RAIL_INDEX_INVALID) ||
132 (!VOLT_RAIL_INDEX_IS_VALID(&g->perf_pmu.volt, rail_idx))) {
133 gk20a_err(dev_from_gk20a(g),
134 "failed: volt_domain = %d, voltage rail table = %d.",
135 volt_domain, rail_idx);
136 return -EINVAL;
137 }
138
139 /* Set RPC parameters. */
140 rpc_call.function = NV_PMU_VOLT_RPC_ID_VOLT_RAIL_GET_VOLTAGE;
141 rpc_call.params.volt_rail_get_voltage.rail_idx = rail_idx;
142
143 /* Execute the voltage get request via PMU RPC. */
144 status = volt_pmu_rpc_execute(g, &rpc_call);
145 if (status) {
146 gk20a_err(dev_from_gk20a(g),
147 "Error while executing volt_rail_get_voltage rpc");
148 return status;
149 }
150
151 /* Copy out the current voltage. */
152 *pvoltage_uv = rpc_call.params.volt_rail_get_voltage.voltage_uv;
153
154 return status;
155}
156
157
158static u32 volt_policy_set_voltage(struct gk20a *g, u8 client_id,
159 struct ctrl_perf_volt_rail_list *prail_list)
160{
161 struct nv_pmu_volt_rpc rpc_call = { 0 };
162 struct obj_volt *pvolt = &g->perf_pmu.volt;
163 u32 status = 0;
164 u8 policy_idx = CTRL_VOLT_POLICY_INDEX_INVALID;
165 u8 i = 0;
166
167 /* Sanity check input rail list. */
168 for (i = 0; i < prail_list->num_rails; i++) {
169 if ((prail_list->rails[i].volt_domain ==
170 CTRL_VOLT_DOMAIN_INVALID) ||
171 (prail_list->rails[i].voltage_uv ==
172 NV_PMU_VOLT_VALUE_0V_IN_UV)) {
173 gk20a_err(dev_from_gk20a(g), "Invalid voltage domain or target ");
174 gk20a_err(dev_from_gk20a(g), " client_id = %d, listEntry = %d ",
175 client_id, i);
176 gk20a_err(dev_from_gk20a(g),
177 "volt_domain = %d, voltage_uv = %d uV.",
178 prail_list->rails[i].volt_domain,
179 prail_list->rails[i].voltage_uv);
180 status = -EINVAL;
181 goto exit;
182 }
183 }
184
185 /* Convert the client ID to index. */
186 if (client_id == CTRL_VOLT_POLICY_CLIENT_PERF_CORE_VF_SEQ)
187 policy_idx =
188 pvolt->volt_policy_metadata.perf_core_vf_seq_policy_idx;
189 else {
190 status = -EINVAL;
191 goto exit;
192 }
193
194 /* Set RPC parameters. */
195 rpc_call.function = NV_PMU_VOLT_RPC_ID_VOLT_POLICY_SET_VOLTAGE;
196 rpc_call.params.volt_policy_voltage_data.policy_idx = policy_idx;
197 memcpy(&rpc_call.params.volt_policy_voltage_data.rail_list, prail_list,
198 (sizeof(struct ctrl_perf_volt_rail_list)));
199
200 /* Execute the voltage change request via PMU RPC. */
201 status = volt_pmu_rpc_execute(g, &rpc_call);
202 if (status)
203 gk20a_err(dev_from_gk20a(g),
204 "Error while executing VOLT_POLICY_SET_VOLTAGE RPC");
205
206exit:
207 return status;
208}
209
210u32 volt_set_voltage(struct gk20a *g, u32 logic_voltage_uv, u32 sram_voltage_uv)
211{
212 u32 status = 0;
213 struct ctrl_perf_volt_rail_list rail_list = { 0 };
214
215 rail_list.num_rails = RAIL_COUNT;
216 rail_list.rails[0].volt_domain = CTRL_VOLT_DOMAIN_LOGIC;
217 rail_list.rails[0].voltage_uv = logic_voltage_uv;
218 rail_list.rails[0].voltage_min_noise_unaware_uv = logic_voltage_uv;
219 rail_list.rails[1].volt_domain = CTRL_VOLT_DOMAIN_SRAM;
220 rail_list.rails[1].voltage_uv = sram_voltage_uv;
221 rail_list.rails[1].voltage_min_noise_unaware_uv = sram_voltage_uv;
222
223 status = volt_policy_set_voltage(g,
224 CTRL_VOLT_POLICY_CLIENT_PERF_CORE_VF_SEQ, &rail_list);
225
226 return status;
227
228}
229
230u32 volt_get_voltage(struct gk20a *g, u32 volt_domain)
231{
232 u32 status = 0;
233 u32 voltage_uv = 0;
234
235 status = volt_rail_get_voltage(g, volt_domain, &voltage_uv);
236 if (status) {
237 gk20a_err(dev_from_gk20a(g),
238 "CTRL_VOLT_DOMAIN_LOGIC get voltage failed");
239 return 0;
240 }
241
242 return voltage_uv;
243}