diff options
Diffstat (limited to 'drivers/gpu/nvgpu/clk/clk.c')
-rw-r--r-- | drivers/gpu/nvgpu/clk/clk.c | 229 |
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 | ||
107 | u32 clk_pmu_vf_inject(struct gk20a *g) | 107 | static 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 | ||
205 | static 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 | |||
224 | static 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 | |||
240 | static 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 | |||
256 | int 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; | ||
376 | done: | ||
377 | mutex_unlock(&pclk->changeclkmutex); | ||
378 | return status; | ||
379 | } | ||
380 | |||
381 | int 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 | |||
192 | u32 clk_domain_print_vf_table(struct gk20a *g, u32 clkapidomain) | 397 | u32 clk_domain_print_vf_table(struct gk20a *g, u32 clkapidomain) |
193 | { | 398 | { |
194 | u32 status = -EINVAL; | 399 | u32 status = -EINVAL; |