summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/clk/clk.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/nvgpu/clk/clk.c')
-rw-r--r--drivers/gpu/nvgpu/clk/clk.c229
1 files changed, 217 insertions, 12 deletions
diff --git a/drivers/gpu/nvgpu/clk/clk.c b/drivers/gpu/nvgpu/clk/clk.c
index 7ee4f283..918cd43c 100644
--- a/drivers/gpu/nvgpu/clk/clk.c
+++ b/drivers/gpu/nvgpu/clk/clk.c
@@ -104,7 +104,7 @@ done:
104 return status; 104 return status;
105} 105}
106 106
107u32 clk_pmu_vf_inject(struct gk20a *g) 107static u32 clk_pmu_vf_inject(struct gk20a *g, struct set_fll_clk *setfllclk)
108{ 108{
109 struct pmu_cmd cmd; 109 struct pmu_cmd cmd;
110 struct pmu_msg msg; 110 struct pmu_msg msg;
@@ -115,35 +115,48 @@ u32 clk_pmu_vf_inject(struct gk20a *g)
115 struct clkrpc_pmucmdhandler_params handler = {0}; 115 struct clkrpc_pmucmdhandler_params handler = {0};
116 struct nv_pmu_clk_vf_change_inject *vfchange; 116 struct nv_pmu_clk_vf_change_inject *vfchange;
117 117
118 if ((setfllclk->gpc2clkmhz == 0) || (setfllclk->xbar2clkmhz == 0) ||
119 (setfllclk->sys2clkmhz == 0) || (setfllclk->voltuv == 0))
120 return -EINVAL;
121
122 if ((setfllclk->target_regime_id_gpc > CTRL_CLK_FLL_REGIME_ID_FR) ||
123 (setfllclk->target_regime_id_sys > CTRL_CLK_FLL_REGIME_ID_FR) ||
124 (setfllclk->target_regime_id_xbar > CTRL_CLK_FLL_REGIME_ID_FR))
125 return -EINVAL;
126
118 rpccall.function = NV_PMU_CLK_RPC_ID_CLK_VF_CHANGE_INJECT; 127 rpccall.function = NV_PMU_CLK_RPC_ID_CLK_VF_CHANGE_INJECT;
119 vfchange = &rpccall.params.clk_vf_change_inject; 128 vfchange = &rpccall.params.clk_vf_change_inject;
120 vfchange->flags = 0; 129 vfchange->flags = 0;
121 vfchange->clk_list.num_domains = 3; 130 vfchange->clk_list.num_domains = 3;
122 vfchange->clk_list.clk_domains[0].clk_domain = CTRL_CLK_DOMAIN_GPC2CLK; 131 vfchange->clk_list.clk_domains[0].clk_domain = CTRL_CLK_DOMAIN_GPC2CLK;
123 vfchange->clk_list.clk_domains[0].clk_freq_khz = 2581 * 1000; 132 vfchange->clk_list.clk_domains[0].clk_freq_khz =
133 setfllclk->gpc2clkmhz * 1000;
124 vfchange->clk_list.clk_domains[0].clk_flags = 0; 134 vfchange->clk_list.clk_domains[0].clk_flags = 0;
125 vfchange->clk_list.clk_domains[0].current_regime_id = 135 vfchange->clk_list.clk_domains[0].current_regime_id =
126 CTRL_CLK_FLL_REGIME_ID_FFR; 136 setfllclk->current_regime_id_gpc;
127 vfchange->clk_list.clk_domains[0].target_regime_id = 137 vfchange->clk_list.clk_domains[0].target_regime_id =
128 CTRL_CLK_FLL_REGIME_ID_FR; 138 setfllclk->target_regime_id_gpc;
129 vfchange->clk_list.clk_domains[1].clk_domain = CTRL_CLK_DOMAIN_XBAR2CLK; 139 vfchange->clk_list.clk_domains[1].clk_domain = CTRL_CLK_DOMAIN_XBAR2CLK;
130 vfchange->clk_list.clk_domains[1].clk_freq_khz = 2505 * 1000; 140 vfchange->clk_list.clk_domains[1].clk_freq_khz =
141 setfllclk->xbar2clkmhz * 1000;
131 vfchange->clk_list.clk_domains[1].clk_flags = 0; 142 vfchange->clk_list.clk_domains[1].clk_flags = 0;
132 vfchange->clk_list.clk_domains[1].current_regime_id = 143 vfchange->clk_list.clk_domains[1].current_regime_id =
133 CTRL_CLK_FLL_REGIME_ID_FFR; 144 setfllclk->current_regime_id_xbar;
134 vfchange->clk_list.clk_domains[1].target_regime_id = 145 vfchange->clk_list.clk_domains[1].target_regime_id =
135 CTRL_CLK_FLL_REGIME_ID_FR; 146 setfllclk->target_regime_id_xbar;
136 vfchange->clk_list.clk_domains[2].clk_domain = CTRL_CLK_DOMAIN_SYS2CLK; 147 vfchange->clk_list.clk_domains[2].clk_domain = CTRL_CLK_DOMAIN_SYS2CLK;
137 vfchange->clk_list.clk_domains[2].clk_freq_khz = 2328 * 1000; 148 vfchange->clk_list.clk_domains[2].clk_freq_khz =
149 setfllclk->sys2clkmhz * 1000;
138 vfchange->clk_list.clk_domains[2].clk_flags = 0; 150 vfchange->clk_list.clk_domains[2].clk_flags = 0;
139 vfchange->clk_list.clk_domains[2].current_regime_id = 151 vfchange->clk_list.clk_domains[2].current_regime_id =
140 CTRL_CLK_FLL_REGIME_ID_FFR; 152 setfllclk->current_regime_id_sys;
141 vfchange->clk_list.clk_domains[2].target_regime_id = 153 vfchange->clk_list.clk_domains[2].target_regime_id =
142 CTRL_CLK_FLL_REGIME_ID_FR; 154 setfllclk->target_regime_id_sys;
143 vfchange->volt_list.num_rails = 1; 155 vfchange->volt_list.num_rails = 1;
144 vfchange->volt_list.rails[0].volt_domain = CTRL_VOLT_DOMAIN_LOGIC; 156 vfchange->volt_list.rails[0].volt_domain = CTRL_VOLT_DOMAIN_LOGIC;
145 vfchange->volt_list.rails[0].voltage_uv = 825000; 157 vfchange->volt_list.rails[0].voltage_uv = setfllclk->voltuv;
146 vfchange->volt_list.rails[0].voltage_min_noise_unaware_uv = 825000; 158 vfchange->volt_list.rails[0].voltage_min_noise_unaware_uv =
159 setfllclk->voltuv;
147 160
148 cmd.hdr.unit_id = PMU_UNIT_CLK; 161 cmd.hdr.unit_id = PMU_UNIT_CLK;
149 cmd.hdr.size = (u32)sizeof(struct nv_pmu_clk_cmd) + 162 cmd.hdr.size = (u32)sizeof(struct nv_pmu_clk_cmd) +
@@ -189,6 +202,198 @@ done:
189 return status; 202 return status;
190} 203}
191 204
205static u32 find_regime_id(struct gk20a *g, u32 domain, u16 clkmhz)
206{
207 struct fll_device *pflldev;
208 u8 j;
209 struct clk_pmupstate *pclk = &g->clk_pmu;
210
211 BOARDOBJGRP_FOR_EACH(&(pclk->avfs_fllobjs.super.super),
212 struct fll_device *, pflldev, j) {
213 if (pflldev->clk_domain == domain) {
214 if (pflldev->regime_desc.fixed_freq_regime_limit_mhz >=
215 clkmhz)
216 return CTRL_CLK_FLL_REGIME_ID_FR;
217 else
218 return CTRL_CLK_FLL_REGIME_ID_FFR;
219 }
220 }
221 return CTRL_CLK_FLL_REGIME_ID_INVALID;
222}
223
224static int set_regime_id(struct gk20a *g, u32 domain, u32 regimeid)
225{
226 struct fll_device *pflldev;
227 u8 j;
228 struct clk_pmupstate *pclk = &g->clk_pmu;
229
230 BOARDOBJGRP_FOR_EACH(&(pclk->avfs_fllobjs.super.super),
231 struct fll_device *, pflldev, j) {
232 if (pflldev->clk_domain == domain) {
233 pflldev->regime_desc.regime_id = regimeid;
234 return 0;
235 }
236 }
237 return -EINVAL;
238}
239
240static int get_regime_id(struct gk20a *g, u32 domain, u32 *regimeid)
241{
242 struct fll_device *pflldev;
243 u8 j;
244 struct clk_pmupstate *pclk = &g->clk_pmu;
245
246 BOARDOBJGRP_FOR_EACH(&(pclk->avfs_fllobjs.super.super),
247 struct fll_device *, pflldev, j) {
248 if (pflldev->clk_domain == domain) {
249 *regimeid = pflldev->regime_desc.regime_id;
250 return 0;
251 }
252 }
253 return -EINVAL;
254}
255
256int clk_program_fllclks(struct gk20a *g, struct change_fll_clk *fllclk)
257{
258 int status = -EINVAL;
259 struct clk_domain *pdomain;
260 u8 i;
261 struct clk_pmupstate *pclk = &g->clk_pmu;
262 u16 clkmhz = 0;
263 struct clk_domain_3x_master *p3xmaster;
264 struct clk_domain_3x_slave *p3xslave;
265 unsigned long slaveidxmask;
266 struct set_fll_clk setfllclk;
267 bool foundxbar2clk = false;
268 bool foundsys2clk = false;
269
270 memset(&setfllclk, 0, sizeof(setfllclk));
271 if (fllclk->api_clk_domain != CTRL_CLK_DOMAIN_GPC2CLK)
272 return -EINVAL;
273 if (fllclk->voltuv == 0)
274 return -EINVAL;
275 if (fllclk->clkmhz == 0)
276 return -EINVAL;
277
278 mutex_lock(&pclk->changeclkmutex);
279
280 setfllclk.voltuv = fllclk->voltuv;
281 setfllclk.gpc2clkmhz = fllclk->clkmhz;
282
283 BOARDOBJGRP_FOR_EACH(&(pclk->clk_domainobjs.super.super),
284 struct clk_domain *, pdomain, i) {
285
286 if (pdomain->api_domain == fllclk->api_clk_domain) {
287
288 if (!pdomain->super.implements(g, &pdomain->super,
289 CTRL_CLK_CLK_DOMAIN_TYPE_3X_MASTER)) {
290 status = -EINVAL;
291 goto done;
292 }
293 p3xmaster = (struct clk_domain_3x_master *)pdomain;
294 slaveidxmask = p3xmaster->slave_idxs_mask;
295 for_each_set_bit(i, &slaveidxmask, 32) {
296 p3xslave = (struct clk_domain_3x_slave *)
297 CLK_CLK_DOMAIN_GET(pclk, i);
298 if ((p3xslave->super.super.super.api_domain !=
299 CTRL_CLK_DOMAIN_XBAR2CLK) &&
300 (p3xslave->super.super.super.api_domain !=
301 CTRL_CLK_DOMAIN_SYS2CLK))
302 continue;
303 clkmhz = 0;
304 status = p3xslave->clkdomainclkgetslaveclk(g,
305 pclk,
306 (struct clk_domain *)p3xslave,
307 &clkmhz,
308 fllclk->clkmhz);
309 if (status) {
310 status = -EINVAL;
311 goto done;
312 }
313 if (p3xslave->super.super.super.api_domain ==
314 CTRL_CLK_DOMAIN_XBAR2CLK) {
315 setfllclk.xbar2clkmhz = clkmhz;
316 foundxbar2clk = true;
317 }
318 if (p3xslave->super.super.super.api_domain ==
319 CTRL_CLK_DOMAIN_SYS2CLK) {
320 setfllclk.sys2clkmhz = clkmhz;
321 foundsys2clk = true;
322 }
323 }
324 }
325 }
326 if (!(foundxbar2clk && foundsys2clk)) {
327 status = -EINVAL;
328 goto done;
329 }
330 /*set regime ids */
331 status = get_regime_id(g, CTRL_CLK_DOMAIN_GPC2CLK,
332 &setfllclk.current_regime_id_gpc);
333 if (status)
334 goto done;
335
336 setfllclk.target_regime_id_gpc = find_regime_id(g,
337 CTRL_CLK_DOMAIN_GPC2CLK, setfllclk.gpc2clkmhz);
338
339 status = get_regime_id(g, CTRL_CLK_DOMAIN_SYS2CLK,
340 &setfllclk.current_regime_id_sys);
341 if (status)
342 goto done;
343
344 setfllclk.target_regime_id_sys = find_regime_id(g,
345 CTRL_CLK_DOMAIN_SYS2CLK, setfllclk.sys2clkmhz);
346
347 status = get_regime_id(g, CTRL_CLK_DOMAIN_XBAR2CLK,
348 &setfllclk.current_regime_id_xbar);
349 if (status)
350 goto done;
351
352 setfllclk.target_regime_id_xbar = find_regime_id(g,
353 CTRL_CLK_DOMAIN_XBAR2CLK, setfllclk.xbar2clkmhz);
354
355 status = clk_pmu_vf_inject(g, &setfllclk);
356
357 if (status)
358 gk20a_err(dev_from_gk20a(g),
359 "vf inject to change clk failed");
360
361 /* save regime ids */
362 status = set_regime_id(g, CTRL_CLK_DOMAIN_XBAR2CLK,
363 setfllclk.target_regime_id_xbar);
364 if (status)
365 goto done;
366
367 status = set_regime_id(g, CTRL_CLK_DOMAIN_GPC2CLK,
368 setfllclk.target_regime_id_gpc);
369 if (status)
370 goto done;
371
372 status = set_regime_id(g, CTRL_CLK_DOMAIN_SYS2CLK,
373 setfllclk.target_regime_id_sys);
374 if (status)
375 goto done;
376done:
377 mutex_unlock(&pclk->changeclkmutex);
378 return status;
379}
380
381int clk_set_boot_fll_clk(struct gk20a *g)
382{
383 int status;
384 struct change_fll_clk bootfllclk;
385
386 mutex_init(&g->clk_pmu.changeclkmutex);
387
388 bootfllclk.api_clk_domain = CTRL_CLK_DOMAIN_GPC2CLK;
389 bootfllclk.clkmhz = 2581;
390 bootfllclk.voltuv = 825000;
391 status = clk_program_fllclks(g, &bootfllclk);
392 if (status)
393 gk20a_err(dev_from_gk20a(g), "attemp to set boot clk failed");
394 return status;
395}
396
192u32 clk_domain_print_vf_table(struct gk20a *g, u32 clkapidomain) 397u32 clk_domain_print_vf_table(struct gk20a *g, u32 clkapidomain)
193{ 398{
194 u32 status = -EINVAL; 399 u32 status = -EINVAL;