diff options
Diffstat (limited to 'drivers/gpu/nvgpu/clk')
-rw-r--r-- | drivers/gpu/nvgpu/clk/clk.c | 229 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/clk/clk.h | 24 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/clk/clk_domain.c | 69 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/clk/clk_domain.h | 7 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/clk/clk_prog.c | 55 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/clk/clk_prog.h | 6 |
6 files changed, 356 insertions, 34 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; |
diff --git a/drivers/gpu/nvgpu/clk/clk.h b/drivers/gpu/nvgpu/clk/clk.h index 1f25fa4e..e54af521 100644 --- a/drivers/gpu/nvgpu/clk/clk.h +++ b/drivers/gpu/nvgpu/clk/clk.h | |||
@@ -35,6 +35,7 @@ struct clk_pmupstate { | |||
35 | struct clk_progs clk_progobjs; | 35 | struct clk_progs clk_progobjs; |
36 | struct clk_vf_points clk_vf_pointobjs; | 36 | struct clk_vf_points clk_vf_pointobjs; |
37 | struct clk_mclk_state clk_mclk; | 37 | struct clk_mclk_state clk_mclk; |
38 | struct mutex changeclkmutex; | ||
38 | }; | 39 | }; |
39 | 40 | ||
40 | struct clockentry { | 41 | struct clockentry { |
@@ -44,6 +45,25 @@ struct clockentry { | |||
44 | u32 api_clk_domain; | 45 | u32 api_clk_domain; |
45 | }; | 46 | }; |
46 | 47 | ||
48 | struct change_fll_clk { | ||
49 | u32 api_clk_domain; | ||
50 | u16 clkmhz; | ||
51 | u32 voltuv; | ||
52 | }; | ||
53 | |||
54 | struct set_fll_clk { | ||
55 | u32 voltuv; | ||
56 | u16 gpc2clkmhz; | ||
57 | u32 current_regime_id_gpc; | ||
58 | u32 target_regime_id_gpc; | ||
59 | u16 sys2clkmhz; | ||
60 | u32 current_regime_id_sys; | ||
61 | u32 target_regime_id_sys; | ||
62 | u16 xbar2clkmhz; | ||
63 | u32 current_regime_id_xbar; | ||
64 | u32 target_regime_id_xbar; | ||
65 | }; | ||
66 | |||
47 | #define NV_PERF_HEADER_4X_CLOCKS_DOMAINS_MAX_NUMCLKS 9 | 67 | #define NV_PERF_HEADER_4X_CLOCKS_DOMAINS_MAX_NUMCLKS 9 |
48 | 68 | ||
49 | struct vbios_clock_domain { | 69 | struct vbios_clock_domain { |
@@ -82,7 +102,6 @@ struct vbios_clocks_table_1x_hal_clock_entry { | |||
82 | #define PERF_CLK_PCIEGENCLK 12 | 102 | #define PERF_CLK_PCIEGENCLK 12 |
83 | #define PERF_CLK_NUM 13 | 103 | #define PERF_CLK_NUM 13 |
84 | 104 | ||
85 | u32 clk_pmu_vf_inject(struct gk20a *g); | ||
86 | u32 clk_pmu_vin_load(struct gk20a *g); | 105 | u32 clk_pmu_vin_load(struct gk20a *g); |
87 | u32 clk_domain_print_vf_table(struct gk20a *g, u32 clkapidomain); | 106 | u32 clk_domain_print_vf_table(struct gk20a *g, u32 clkapidomain); |
88 | u32 clk_domain_get_f_or_v | 107 | u32 clk_domain_get_f_or_v |
@@ -98,5 +117,6 @@ u32 clk_domain_get_f_points( | |||
98 | u32 *fpointscount, | 117 | u32 *fpointscount, |
99 | u16 *freqpointsinmhz | 118 | u16 *freqpointsinmhz |
100 | ); | 119 | ); |
101 | 120 | int clk_set_boot_fll_clk(struct gk20a *g); | |
121 | int clk_program_fll_clks(struct gk20a *g, struct change_fll_clk *fllclk); | ||
102 | #endif | 122 | #endif |
diff --git a/drivers/gpu/nvgpu/clk/clk_domain.c b/drivers/gpu/nvgpu/clk/clk_domain.c index f87530dc..fe3db5d6 100644 --- a/drivers/gpu/nvgpu/clk/clk_domain.c +++ b/drivers/gpu/nvgpu/clk/clk_domain.c | |||
@@ -422,14 +422,14 @@ static u32 clkdomainclkproglink_not_supported(struct gk20a *g, | |||
422 | return -EINVAL; | 422 | return -EINVAL; |
423 | } | 423 | } |
424 | 424 | ||
425 | static u32 clkdomainvfsearch_stub( | 425 | static int clkdomainvfsearch_stub( |
426 | struct gk20a *g, | 426 | struct gk20a *g, |
427 | struct clk_pmupstate *pclk, | 427 | struct clk_pmupstate *pclk, |
428 | struct clk_domain *pdomain, | 428 | struct clk_domain *pdomain, |
429 | u16 *clkmhz, | 429 | u16 *clkmhz, |
430 | u32 *voltuv, | 430 | u32 *voltuv, |
431 | u8 rail | 431 | u8 rail) |
432 | ) | 432 | |
433 | { | 433 | { |
434 | gk20a_dbg_info(""); | 434 | gk20a_dbg_info(""); |
435 | return -EINVAL; | 435 | return -EINVAL; |
@@ -441,8 +441,7 @@ static u32 clkdomaingetfpoints_stub( | |||
441 | struct clk_domain *pdomain, | 441 | struct clk_domain *pdomain, |
442 | u32 *pfpointscount, | 442 | u32 *pfpointscount, |
443 | u16 *pfreqpointsinmhz, | 443 | u16 *pfreqpointsinmhz, |
444 | u8 rail | 444 | u8 rail) |
445 | ) | ||
446 | { | 445 | { |
447 | gk20a_dbg_info(""); | 446 | gk20a_dbg_info(""); |
448 | return -EINVAL; | 447 | return -EINVAL; |
@@ -556,17 +555,47 @@ static u32 clkdomainclkproglink_3x_prog(struct gk20a *g, | |||
556 | return status; | 555 | return status; |
557 | } | 556 | } |
558 | 557 | ||
559 | static u32 clkdomainvfsearch | 558 | static int clkdomaingetslaveclk(struct gk20a *g, |
560 | ( | 559 | struct clk_pmupstate *pclk, |
561 | struct gk20a *g, | 560 | struct clk_domain *pdomain, |
562 | struct clk_pmupstate *pclk, | 561 | u16 *pclkmhz, |
563 | struct clk_domain *pdomain, | 562 | u16 masterclkmhz) |
564 | u16 *pclkmhz, | ||
565 | u32 *pvoltuv, | ||
566 | u8 rail | ||
567 | ) | ||
568 | { | 563 | { |
569 | u32 status = 0; | 564 | int status = 0; |
565 | struct clk_prog *pprog = NULL; | ||
566 | struct clk_prog_1x_master *pprog1xmaster = NULL; | ||
567 | u8 slaveidx; | ||
568 | struct clk_domain_3x_master *p3xmaster; | ||
569 | |||
570 | gk20a_dbg_info(""); | ||
571 | |||
572 | if (pclkmhz == NULL) | ||
573 | return -EINVAL; | ||
574 | |||
575 | if (masterclkmhz == 0) | ||
576 | return -EINVAL; | ||
577 | |||
578 | slaveidx = BOARDOBJ_GET_IDX(pdomain); | ||
579 | p3xmaster = (struct clk_domain_3x_master *) | ||
580 | CLK_CLK_DOMAIN_GET(pclk, | ||
581 | ((struct clk_domain_3x_slave *) | ||
582 | pdomain)->master_idx); | ||
583 | pprog = CLK_CLK_PROG_GET(pclk, p3xmaster->super.clk_prog_idx_first); | ||
584 | pprog1xmaster = (struct clk_prog_1x_master *)pprog; | ||
585 | |||
586 | status = pprog1xmaster->getslaveclk(g, pclk, pprog1xmaster, | ||
587 | slaveidx, pclkmhz, masterclkmhz); | ||
588 | return status; | ||
589 | } | ||
590 | |||
591 | static int clkdomainvfsearch(struct gk20a *g, | ||
592 | struct clk_pmupstate *pclk, | ||
593 | struct clk_domain *pdomain, | ||
594 | u16 *pclkmhz, | ||
595 | u32 *pvoltuv, | ||
596 | u8 rail) | ||
597 | { | ||
598 | int status = 0; | ||
570 | struct clk_domain_3x_master *p3xmaster = | 599 | struct clk_domain_3x_master *p3xmaster = |
571 | (struct clk_domain_3x_master *)pdomain; | 600 | (struct clk_domain_3x_master *)pdomain; |
572 | struct clk_prog *pprog = NULL; | 601 | struct clk_prog *pprog = NULL; |
@@ -580,6 +609,10 @@ static u32 clkdomainvfsearch | |||
580 | u32 bestvoltuv; | 609 | u32 bestvoltuv; |
581 | 610 | ||
582 | gk20a_dbg_info(""); | 611 | gk20a_dbg_info(""); |
612 | |||
613 | if ((pclkmhz == NULL) || (pvoltuv == NULL)) | ||
614 | return -EINVAL; | ||
615 | |||
583 | if ((*pclkmhz != 0) && (*pvoltuv != 0)) | 616 | if ((*pclkmhz != 0) && (*pvoltuv != 0)) |
584 | return -EINVAL; | 617 | return -EINVAL; |
585 | 618 | ||
@@ -595,7 +628,6 @@ static u32 clkdomainvfsearch | |||
595 | ((struct clk_domain_3x_slave *) | 628 | ((struct clk_domain_3x_slave *) |
596 | pdomain)->master_idx); | 629 | pdomain)->master_idx); |
597 | } | 630 | } |
598 | |||
599 | /* Iterate over the set of CLK_PROGs pointed at by this domain.*/ | 631 | /* Iterate over the set of CLK_PROGs pointed at by this domain.*/ |
600 | for (i = p3xmaster->super.clk_prog_idx_first; | 632 | for (i = p3xmaster->super.clk_prog_idx_first; |
601 | i <= p3xmaster->super.clk_prog_idx_last; | 633 | i <= p3xmaster->super.clk_prog_idx_last; |
@@ -625,7 +657,7 @@ static u32 clkdomainvfsearch | |||
625 | } | 657 | } |
626 | } | 658 | } |
627 | } | 659 | } |
628 | /* clk and volt sent as zero to pring vf table */ | 660 | /* clk and volt sent as zero to print vf table */ |
629 | if ((*pclkmhz == 0) && (*pvoltuv == 0)) { | 661 | if ((*pclkmhz == 0) && (*pvoltuv == 0)) { |
630 | status = 0; | 662 | status = 0; |
631 | goto done; | 663 | goto done; |
@@ -836,6 +868,9 @@ static u32 clk_domain_construct_3x_slave(struct gk20a *g, | |||
836 | 868 | ||
837 | pdomain->master_idx = ptmpdomain->master_idx; | 869 | pdomain->master_idx = ptmpdomain->master_idx; |
838 | 870 | ||
871 | pdomain->clkdomainclkgetslaveclk = | ||
872 | clkdomaingetslaveclk; | ||
873 | |||
839 | return status; | 874 | return status; |
840 | } | 875 | } |
841 | 876 | ||
diff --git a/drivers/gpu/nvgpu/clk/clk_domain.h b/drivers/gpu/nvgpu/clk/clk_domain.h index eeb7c256..443e1c4c 100644 --- a/drivers/gpu/nvgpu/clk/clk_domain.h +++ b/drivers/gpu/nvgpu/clk/clk_domain.h | |||
@@ -30,10 +30,14 @@ u32 clk_domain_pmu_setup(struct gk20a *g); | |||
30 | typedef u32 clkproglink(struct gk20a *g, struct clk_pmupstate *pclk, | 30 | typedef u32 clkproglink(struct gk20a *g, struct clk_pmupstate *pclk, |
31 | struct clk_domain *pdomain); | 31 | struct clk_domain *pdomain); |
32 | 32 | ||
33 | typedef u32 clkvfsearch(struct gk20a *g, struct clk_pmupstate *pclk, | 33 | typedef int clkvfsearch(struct gk20a *g, struct clk_pmupstate *pclk, |
34 | struct clk_domain *pdomain, u16 *clkmhz, | 34 | struct clk_domain *pdomain, u16 *clkmhz, |
35 | u32 *voltuv, u8 rail); | 35 | u32 *voltuv, u8 rail); |
36 | 36 | ||
37 | typedef int clkgetslaveclk(struct gk20a *g, struct clk_pmupstate *pclk, | ||
38 | struct clk_domain *pdomain, u16 *clkmhz, | ||
39 | u16 masterclkmhz); | ||
40 | |||
37 | typedef u32 clkgetfpoints(struct gk20a *g, struct clk_pmupstate *pclk, | 41 | typedef u32 clkgetfpoints(struct gk20a *g, struct clk_pmupstate *pclk, |
38 | struct clk_domain *pdomain, u32 *pfpointscount, | 42 | struct clk_domain *pdomain, u32 *pfpointscount, |
39 | u16 *pfreqpointsinmhz, u8 rail); | 43 | u16 *pfreqpointsinmhz, u8 rail); |
@@ -100,6 +104,7 @@ struct clk_domain_3x_master { | |||
100 | struct clk_domain_3x_slave { | 104 | struct clk_domain_3x_slave { |
101 | struct clk_domain_3x_prog super; | 105 | struct clk_domain_3x_prog super; |
102 | u8 master_idx; | 106 | u8 master_idx; |
107 | clkgetslaveclk *clkdomainclkgetslaveclk; | ||
103 | }; | 108 | }; |
104 | 109 | ||
105 | u32 clk_domain_clk_prog_link(struct gk20a *g, struct clk_pmupstate *pclk); | 110 | u32 clk_domain_clk_prog_link(struct gk20a *g, struct clk_pmupstate *pclk); |
diff --git a/drivers/gpu/nvgpu/clk/clk_prog.c b/drivers/gpu/nvgpu/clk/clk_prog.c index cb9a0e8d..9fdd8b25 100644 --- a/drivers/gpu/nvgpu/clk/clk_prog.c +++ b/drivers/gpu/nvgpu/clk/clk_prog.c | |||
@@ -31,6 +31,7 @@ static u32 devinit_get_clk_prog_table(struct gk20a *g, | |||
31 | static vf_flatten vfflatten_prog_1x_master; | 31 | static vf_flatten vfflatten_prog_1x_master; |
32 | static vf_lookup vflookup_prog_1x_master; | 32 | static vf_lookup vflookup_prog_1x_master; |
33 | static get_fpoints getfpoints_prog_1x_master; | 33 | static get_fpoints getfpoints_prog_1x_master; |
34 | static get_slaveclk getslaveclk_prog_1x_master; | ||
34 | 35 | ||
35 | static u32 _clk_progs_pmudatainit(struct gk20a *g, | 36 | static u32 _clk_progs_pmudatainit(struct gk20a *g, |
36 | struct boardobjgrp *pboardobjgrp, | 37 | struct boardobjgrp *pboardobjgrp, |
@@ -611,6 +612,9 @@ static u32 clk_prog_construct_1x_master(struct gk20a *g, | |||
611 | pclkprog->getfpoints = | 612 | pclkprog->getfpoints = |
612 | getfpoints_prog_1x_master; | 613 | getfpoints_prog_1x_master; |
613 | 614 | ||
615 | pclkprog->getslaveclk = | ||
616 | getslaveclk_prog_1x_master; | ||
617 | |||
614 | pclkprog->p_vf_entries = (struct ctrl_clk_clk_prog_1x_master_vf_entry *) | 618 | pclkprog->p_vf_entries = (struct ctrl_clk_clk_prog_1x_master_vf_entry *) |
615 | kzalloc(vfsize, GFP_KERNEL); | 619 | kzalloc(vfsize, GFP_KERNEL); |
616 | 620 | ||
@@ -851,7 +855,7 @@ static u32 vflookup_prog_1x_master | |||
851 | u8 rail | 855 | u8 rail |
852 | ) | 856 | ) |
853 | { | 857 | { |
854 | u8 j; | 858 | int j; |
855 | struct ctrl_clk_clk_prog_1x_master_vf_entry | 859 | struct ctrl_clk_clk_prog_1x_master_vf_entry |
856 | *pvfentry; | 860 | *pvfentry; |
857 | struct clk_vf_point *pvfpoint; | 861 | struct clk_vf_point *pvfpoint; |
@@ -860,7 +864,7 @@ static u32 vflookup_prog_1x_master | |||
860 | u16 clkmhz; | 864 | u16 clkmhz; |
861 | u32 voltuv; | 865 | u32 voltuv; |
862 | u8 slaveentrycount; | 866 | u8 slaveentrycount; |
863 | u8 i; | 867 | int i; |
864 | struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry *pslaveents; | 868 | struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry *pslaveents; |
865 | 869 | ||
866 | if ((*pclkmhz != 0) && (*pvoltuv != 0)) | 870 | if ((*pclkmhz != 0) && (*pvoltuv != 0)) |
@@ -1045,3 +1049,50 @@ done: | |||
1045 | *pfpointscount = fpointscount; | 1049 | *pfpointscount = fpointscount; |
1046 | return 0; | 1050 | return 0; |
1047 | } | 1051 | } |
1052 | |||
1053 | static int getslaveclk_prog_1x_master(struct gk20a *g, | ||
1054 | struct clk_pmupstate *pclk, | ||
1055 | struct clk_prog_1x_master *p1xmaster, | ||
1056 | u8 slave_clk_domain, | ||
1057 | u16 *pclkmhz, | ||
1058 | u16 masterclkmhz | ||
1059 | ) | ||
1060 | { | ||
1061 | struct clk_progs *pclkprogobjs; | ||
1062 | struct clk_prog_1x_master_ratio *p1xmasterratio; | ||
1063 | u8 slaveentrycount; | ||
1064 | u8 i; | ||
1065 | struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry *pslaveents; | ||
1066 | |||
1067 | if (pclkmhz == NULL) | ||
1068 | return -EINVAL; | ||
1069 | |||
1070 | if (masterclkmhz == 0) | ||
1071 | return -EINVAL; | ||
1072 | |||
1073 | *pclkmhz = 0; | ||
1074 | pclkprogobjs = &(pclk->clk_progobjs); | ||
1075 | |||
1076 | slaveentrycount = pclkprogobjs->slave_entry_count; | ||
1077 | |||
1078 | if (p1xmaster->super.super.super.implements(g, | ||
1079 | &p1xmaster->super.super.super, | ||
1080 | CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_RATIO)) { | ||
1081 | p1xmasterratio = | ||
1082 | (struct clk_prog_1x_master_ratio *)p1xmaster; | ||
1083 | pslaveents = p1xmasterratio->p_slave_entries; | ||
1084 | for (i = 0; i < slaveentrycount; i++) { | ||
1085 | if (pslaveents->clk_dom_idx == | ||
1086 | slave_clk_domain) | ||
1087 | break; | ||
1088 | pslaveents++; | ||
1089 | } | ||
1090 | if (i == slaveentrycount) | ||
1091 | return -EINVAL; | ||
1092 | *pclkmhz = (masterclkmhz * pslaveents->ratio)/100; | ||
1093 | } else { | ||
1094 | /* only support ratio for now */ | ||
1095 | return -EINVAL; | ||
1096 | } | ||
1097 | return 0; | ||
1098 | } | ||
diff --git a/drivers/gpu/nvgpu/clk/clk_prog.h b/drivers/gpu/nvgpu/clk/clk_prog.h index be92b3fc..60711b4c 100644 --- a/drivers/gpu/nvgpu/clk/clk_prog.h +++ b/drivers/gpu/nvgpu/clk/clk_prog.h | |||
@@ -32,6 +32,11 @@ typedef u32 vf_lookup(struct gk20a *g, struct clk_pmupstate *pclk, | |||
32 | u8 *slave_clk_domain_idx, u16 *pclkmhz, | 32 | u8 *slave_clk_domain_idx, u16 *pclkmhz, |
33 | u32 *pvoltuv, u8 rail); | 33 | u32 *pvoltuv, u8 rail); |
34 | 34 | ||
35 | typedef int get_slaveclk(struct gk20a *g, struct clk_pmupstate *pclk, | ||
36 | struct clk_prog_1x_master *p1xmaster, | ||
37 | u8 slave_clk_domain_idx, u16 *pclkmhz, | ||
38 | u16 masterclkmhz); | ||
39 | |||
35 | typedef u32 get_fpoints(struct gk20a *g, struct clk_pmupstate *pclk, | 40 | typedef u32 get_fpoints(struct gk20a *g, struct clk_pmupstate *pclk, |
36 | struct clk_prog_1x_master *p1xmaster, | 41 | struct clk_prog_1x_master *p1xmaster, |
37 | u32 *pfpointscount, | 42 | u32 *pfpointscount, |
@@ -65,6 +70,7 @@ struct clk_prog_1x_master { | |||
65 | vf_flatten *vfflatten; | 70 | vf_flatten *vfflatten; |
66 | vf_lookup *vflookup; | 71 | vf_lookup *vflookup; |
67 | get_fpoints *getfpoints; | 72 | get_fpoints *getfpoints; |
73 | get_slaveclk *getslaveclk; | ||
68 | }; | 74 | }; |
69 | 75 | ||
70 | struct clk_prog_1x_master_ratio { | 76 | struct clk_prog_1x_master_ratio { |