summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/clk/clk_fll.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/nvgpu/clk/clk_fll.c')
-rw-r--r--drivers/gpu/nvgpu/clk/clk_fll.c444
1 files changed, 444 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/clk/clk_fll.c b/drivers/gpu/nvgpu/clk/clk_fll.c
new file mode 100644
index 00000000..2f05448f
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk_fll.c
@@ -0,0 +1,444 @@
1/*
2 * Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
21 */
22
23#include <nvgpu/bios.h>
24
25#include "gk20a/gk20a.h"
26#include "clk.h"
27#include "clk_fll.h"
28#include "boardobj/boardobjgrp.h"
29#include "boardobj/boardobjgrp_e32.h"
30#include "ctrl/ctrlclk.h"
31#include "ctrl/ctrlvolt.h"
32
33static u32 devinit_get_fll_device_table(struct gk20a *g,
34 struct avfsfllobjs *pfllobjs);
35static struct fll_device *construct_fll_device(struct gk20a *g,
36 void *pargs);
37static u32 fll_device_init_pmudata_super(struct gk20a *g,
38 struct boardobj *board_obj_ptr,
39 struct nv_pmu_boardobj *ppmudata);
40
41static u32 _clk_fll_devgrp_pmudatainit_super(struct gk20a *g,
42 struct boardobjgrp *pboardobjgrp,
43 struct nv_pmu_boardobjgrp_super *pboardobjgrppmu)
44{
45 struct nv_pmu_clk_clk_fll_device_boardobjgrp_set_header *pset =
46 (struct nv_pmu_clk_clk_fll_device_boardobjgrp_set_header *)
47 pboardobjgrppmu;
48 struct avfsfllobjs *pfll_objs = (struct avfsfllobjs *)
49 pboardobjgrp;
50 u32 status = 0;
51
52 gk20a_dbg_info("");
53
54 status = boardobjgrp_pmudatainit_e32(g, pboardobjgrp, pboardobjgrppmu);
55 if (status) {
56 nvgpu_err(g, "failed to init fll pmuobjgrp");
57 return status;
58 }
59 pset->lut_num_entries = pfll_objs->lut_num_entries;
60 pset->lut_step_size_uv = pfll_objs->lut_step_size_uv;
61 pset->lut_min_voltage_uv = pfll_objs->lut_min_voltage_uv;
62 pset->max_min_freq_mhz = pfll_objs->max_min_freq_mhz;
63
64 status = boardobjgrpmask_export(
65 &pfll_objs->lut_prog_master_mask.super,
66 pfll_objs->lut_prog_master_mask.super.bitcount,
67 &pset->lut_prog_master_mask.super);
68
69 gk20a_dbg_info(" Done");
70 return status;
71}
72
73static u32 _clk_fll_devgrp_pmudata_instget(struct gk20a *g,
74 struct nv_pmu_boardobjgrp *pmuboardobjgrp,
75 struct nv_pmu_boardobj **ppboardobjpmudata,
76 u8 idx)
77{
78 struct nv_pmu_clk_clk_fll_device_boardobj_grp_set *pgrp_set =
79 (struct nv_pmu_clk_clk_fll_device_boardobj_grp_set *)
80 pmuboardobjgrp;
81
82 gk20a_dbg_info("");
83
84 /*check whether pmuboardobjgrp has a valid boardobj in index*/
85 if (((u32)BIT(idx) &
86 pgrp_set->hdr.data.super.obj_mask.super.data[0]) == 0)
87 return -EINVAL;
88
89 *ppboardobjpmudata = (struct nv_pmu_boardobj *)
90 &pgrp_set->objects[idx].data.board_obj;
91 gk20a_dbg_info(" Done");
92 return 0;
93}
94
95static u32 _clk_fll_devgrp_pmustatus_instget(struct gk20a *g,
96 void *pboardobjgrppmu,
97 struct nv_pmu_boardobj_query **ppboardobjpmustatus,
98 u8 idx)
99{
100 struct nv_pmu_clk_clk_fll_device_boardobj_grp_get_status *pgrp_get_status =
101 (struct nv_pmu_clk_clk_fll_device_boardobj_grp_get_status *)
102 pboardobjgrppmu;
103
104 /*check whether pmuboardobjgrp has a valid boardobj in index*/
105 if (((u32)BIT(idx) &
106 pgrp_get_status->hdr.data.super.obj_mask.super.data[0]) == 0)
107 return -EINVAL;
108
109 *ppboardobjpmustatus = (struct nv_pmu_boardobj_query *)
110 &pgrp_get_status->objects[idx].data.board_obj;
111 return 0;
112}
113
114u32 clk_fll_sw_setup(struct gk20a *g)
115{
116 u32 status;
117 struct boardobjgrp *pboardobjgrp = NULL;
118 struct avfsfllobjs *pfllobjs;
119 struct fll_device *pfll;
120 struct fll_device *pfll_master;
121 struct fll_device *pfll_local;
122 u8 i;
123 u8 j;
124
125 gk20a_dbg_info("");
126
127 status = boardobjgrpconstruct_e32(g, &g->clk_pmu.avfs_fllobjs.super);
128 if (status) {
129 nvgpu_err(g,
130 "error creating boardobjgrp for fll, status - 0x%x", status);
131 goto done;
132 }
133 pfllobjs = &(g->clk_pmu.avfs_fllobjs);
134 pboardobjgrp = &(g->clk_pmu.avfs_fllobjs.super.super);
135
136 BOARDOBJGRP_PMU_CONSTRUCT(pboardobjgrp, CLK, FLL_DEVICE);
137
138 status = BOARDOBJGRP_PMU_CMD_GRP_SET_CONSTRUCT(g, pboardobjgrp,
139 clk, CLK, clk_fll_device, CLK_FLL_DEVICE);
140 if (status) {
141 nvgpu_err(g,
142 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
143 status);
144 goto done;
145 }
146
147 pboardobjgrp->pmudatainit = _clk_fll_devgrp_pmudatainit_super;
148 pboardobjgrp->pmudatainstget = _clk_fll_devgrp_pmudata_instget;
149 pboardobjgrp->pmustatusinstget = _clk_fll_devgrp_pmustatus_instget;
150 pfllobjs = (struct avfsfllobjs *)pboardobjgrp;
151 pfllobjs->lut_num_entries = CTRL_CLK_LUT_NUM_ENTRIES;
152 pfllobjs->lut_step_size_uv = CTRL_CLK_VIN_STEP_SIZE_UV;
153 pfllobjs->lut_min_voltage_uv = CTRL_CLK_LUT_MIN_VOLTAGE_UV;
154
155 /* Initialize lut prog master mask to zero.*/
156 boardobjgrpmask_e32_init(&pfllobjs->lut_prog_master_mask, NULL);
157
158 status = devinit_get_fll_device_table(g, pfllobjs);
159 if (status)
160 goto done;
161
162 status = BOARDOBJGRP_PMU_CMD_GRP_GET_STATUS_CONSTRUCT(g,
163 &g->clk_pmu.avfs_fllobjs.super.super,
164 clk, CLK, clk_fll_device, CLK_FLL_DEVICE);
165 if (status) {
166 nvgpu_err(g,
167 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
168 status);
169 goto done;
170 }
171
172 BOARDOBJGRP_FOR_EACH(&(pfllobjs->super.super),
173 struct fll_device *, pfll, i) {
174 pfll_master = NULL;
175 j = 0;
176 BOARDOBJGRP_ITERATOR(&(pfllobjs->super.super),
177 struct fll_device *, pfll_local, j,
178 &pfllobjs->lut_prog_master_mask.super) {
179 if (pfll_local->clk_domain == pfll->clk_domain) {
180 pfll_master = pfll_local;
181 break;
182 }
183 }
184
185 if (pfll_master == NULL) {
186 status = boardobjgrpmask_bitset(
187 &pfllobjs->lut_prog_master_mask.super,
188 BOARDOBJ_GET_IDX(pfll));
189 if (status) {
190 nvgpu_err(g, "err setting lutprogmask");
191 goto done;
192 }
193 pfll_master = pfll;
194 }
195 status = pfll_master->lut_broadcast_slave_register(
196 g, pfllobjs, pfll_master, pfll);
197
198 if (status) {
199 nvgpu_err(g, "err setting lutslavemask");
200 goto done;
201 }
202 }
203done:
204 gk20a_dbg_info(" done status %x", status);
205 return status;
206}
207
208u32 clk_fll_pmu_setup(struct gk20a *g)
209{
210 u32 status;
211 struct boardobjgrp *pboardobjgrp = NULL;
212
213 gk20a_dbg_info("");
214
215 pboardobjgrp = &g->clk_pmu.avfs_fllobjs.super.super;
216
217 if (!pboardobjgrp->bconstructed)
218 return -EINVAL;
219
220 status = pboardobjgrp->pmuinithandle(g, pboardobjgrp);
221
222 gk20a_dbg_info("Done");
223 return status;
224}
225
226static u32 devinit_get_fll_device_table(struct gk20a *g,
227 struct avfsfllobjs *pfllobjs)
228{
229 u32 status = 0;
230 u8 *fll_table_ptr = NULL;
231 struct fll_descriptor_header fll_desc_table_header_sz = { 0 };
232 struct fll_descriptor_header_10 fll_desc_table_header = { 0 };
233 struct fll_descriptor_entry_10 fll_desc_table_entry = { 0 };
234 u8 *fll_tbl_entry_ptr = NULL;
235 u32 index = 0;
236 struct fll_device fll_dev_data;
237 struct fll_device *pfll_dev;
238 struct vin_device *pvin_dev;
239 u32 desctablesize;
240 u32 vbios_domain = NV_PERF_DOMAIN_4X_CLOCK_DOMAIN_SKIP;
241 struct avfsvinobjs *pvinobjs = &g->clk_pmu.avfs_vinobjs;
242
243 gk20a_dbg_info("");
244
245 fll_table_ptr = (u8 *)nvgpu_bios_get_perf_table_ptrs(g,
246 g->bios.clock_token, FLL_TABLE);
247 if (fll_table_ptr == NULL) {
248 status = -1;
249 goto done;
250 }
251
252 memcpy(&fll_desc_table_header_sz, fll_table_ptr,
253 sizeof(struct fll_descriptor_header));
254 if (fll_desc_table_header_sz.size >= FLL_DESCRIPTOR_HEADER_10_SIZE_6)
255 desctablesize = FLL_DESCRIPTOR_HEADER_10_SIZE_6;
256 else
257 desctablesize = FLL_DESCRIPTOR_HEADER_10_SIZE_4;
258
259 memcpy(&fll_desc_table_header, fll_table_ptr, desctablesize);
260
261 if (desctablesize == FLL_DESCRIPTOR_HEADER_10_SIZE_6)
262 pfllobjs->max_min_freq_mhz =
263 fll_desc_table_header.max_min_freq_mhz;
264 else
265 pfllobjs->max_min_freq_mhz = 0;
266
267 /* Read table entries*/
268 fll_tbl_entry_ptr = fll_table_ptr + desctablesize;
269 for (index = 0; index < fll_desc_table_header.entry_count; index++) {
270 u32 fll_id;
271
272 memcpy(&fll_desc_table_entry, fll_tbl_entry_ptr,
273 sizeof(struct fll_descriptor_entry_10));
274
275 if (fll_desc_table_entry.fll_device_type == CTRL_CLK_FLL_TYPE_DISABLED)
276 continue;
277
278 fll_id = fll_desc_table_entry.fll_device_id;
279
280 pvin_dev = CLK_GET_VIN_DEVICE(pvinobjs,
281 (u8)fll_desc_table_entry.vin_idx_logic);
282 if (pvin_dev == NULL)
283 return -EINVAL;
284
285 pvin_dev->flls_shared_mask |= BIT(fll_id);
286
287 pvin_dev = CLK_GET_VIN_DEVICE(pvinobjs,
288 (u8)fll_desc_table_entry.vin_idx_sram);
289 if (pvin_dev == NULL)
290 return -EINVAL;
291
292 pvin_dev->flls_shared_mask |= BIT(fll_id);
293
294 fll_dev_data.super.type =
295 (u8)fll_desc_table_entry.fll_device_type;
296 fll_dev_data.id = (u8)fll_desc_table_entry.fll_device_id;
297 fll_dev_data.mdiv = (u8)BIOS_GET_FIELD(
298 fll_desc_table_entry.fll_params,
299 NV_FLL_DESC_FLL_PARAMS_MDIV);
300 fll_dev_data.input_freq_mhz =
301 (u16)fll_desc_table_entry.ref_freq_mhz;
302 fll_dev_data.min_freq_vfe_idx =
303 (u8)fll_desc_table_entry.min_freq_vfe_idx;
304 fll_dev_data.freq_ctrl_idx = CTRL_BOARDOBJ_IDX_INVALID;
305
306 vbios_domain = (u32)(fll_desc_table_entry.clk_domain &
307 NV_PERF_DOMAIN_4X_CLOCK_DOMAIN_MASK);
308 if (vbios_domain == 0)
309 fll_dev_data.clk_domain = CTRL_CLK_DOMAIN_GPC2CLK;
310 else if (vbios_domain == 1)
311 fll_dev_data.clk_domain = CTRL_CLK_DOMAIN_XBAR2CLK;
312 else if (vbios_domain == 3)
313 fll_dev_data.clk_domain = CTRL_CLK_DOMAIN_SYS2CLK;
314 else
315 continue;
316
317 fll_dev_data.rail_idx_for_lut = 0;
318
319 fll_dev_data.vin_idx_logic =
320 (u8)fll_desc_table_entry.vin_idx_logic;
321 fll_dev_data.vin_idx_sram =
322 (u8)fll_desc_table_entry.vin_idx_sram;
323 fll_dev_data.lut_device.vselect_mode =
324 (u8)BIOS_GET_FIELD(fll_desc_table_entry.lut_params,
325 NV_FLL_DESC_LUT_PARAMS_VSELECT);
326 fll_dev_data.lut_device.hysteresis_threshold =
327 (u8)BIOS_GET_FIELD(fll_desc_table_entry.lut_params,
328 NV_FLL_DESC_LUT_PARAMS_HYSTERISIS_THRESHOLD);
329 fll_dev_data.regime_desc.regime_id =
330 CTRL_CLK_FLL_REGIME_ID_FFR;
331 fll_dev_data.regime_desc.fixed_freq_regime_limit_mhz =
332 (u16)fll_desc_table_entry.ffr_cutoff_freq_mhz;
333
334 /*construct fll device*/
335 pfll_dev = construct_fll_device(g, (void *)&fll_dev_data);
336
337 status = boardobjgrp_objinsert(&pfllobjs->super.super,
338 (struct boardobj *)pfll_dev, index);
339
340 fll_tbl_entry_ptr += fll_desc_table_header.entry_size;
341 }
342
343done:
344 gk20a_dbg_info(" done status %x", status);
345 return status;
346}
347
348static u32 lutbroadcastslaveregister(struct gk20a *g,
349 struct avfsfllobjs *pfllobjs,
350 struct fll_device *pfll,
351 struct fll_device *pfll_slave)
352{
353 if (pfll->clk_domain != pfll_slave->clk_domain)
354 return -EINVAL;
355
356 return boardobjgrpmask_bitset(&pfll->
357 lut_prog_broadcast_slave_mask.super,
358 BOARDOBJ_GET_IDX(pfll_slave));
359}
360
361static struct fll_device *construct_fll_device(struct gk20a *g,
362 void *pargs)
363{
364 struct boardobj *board_obj_ptr = NULL;
365 struct fll_device *pfll_dev;
366 struct fll_device *board_obj_fll_ptr = NULL;
367 u32 status;
368
369 gk20a_dbg_info("");
370 status = boardobj_construct_super(g, &board_obj_ptr,
371 sizeof(struct fll_device), pargs);
372 if (status)
373 return NULL;
374
375 pfll_dev = (struct fll_device *)pargs;
376 board_obj_fll_ptr = (struct fll_device *)board_obj_ptr;
377 board_obj_ptr->pmudatainit = fll_device_init_pmudata_super;
378 board_obj_fll_ptr->lut_broadcast_slave_register =
379 lutbroadcastslaveregister;
380 board_obj_fll_ptr->id = pfll_dev->id;
381 board_obj_fll_ptr->mdiv = pfll_dev->mdiv;
382 board_obj_fll_ptr->rail_idx_for_lut = pfll_dev->rail_idx_for_lut;
383 board_obj_fll_ptr->input_freq_mhz = pfll_dev->input_freq_mhz;
384 board_obj_fll_ptr->clk_domain = pfll_dev->clk_domain;
385 board_obj_fll_ptr->vin_idx_logic = pfll_dev->vin_idx_logic;
386 board_obj_fll_ptr->vin_idx_sram = pfll_dev->vin_idx_sram;
387 board_obj_fll_ptr->min_freq_vfe_idx =
388 pfll_dev->min_freq_vfe_idx;
389 board_obj_fll_ptr->freq_ctrl_idx = pfll_dev->freq_ctrl_idx;
390 memcpy(&board_obj_fll_ptr->lut_device, &pfll_dev->lut_device,
391 sizeof(struct nv_pmu_clk_lut_device_desc));
392 memcpy(&board_obj_fll_ptr->regime_desc, &pfll_dev->regime_desc,
393 sizeof(struct nv_pmu_clk_regime_desc));
394 boardobjgrpmask_e32_init(
395 &board_obj_fll_ptr->lut_prog_broadcast_slave_mask, NULL);
396
397 gk20a_dbg_info(" Done");
398
399 return (struct fll_device *)board_obj_ptr;
400}
401
402static u32 fll_device_init_pmudata_super(struct gk20a *g,
403 struct boardobj *board_obj_ptr,
404 struct nv_pmu_boardobj *ppmudata)
405{
406 u32 status = 0;
407 struct fll_device *pfll_dev;
408 struct nv_pmu_clk_clk_fll_device_boardobj_set *perf_pmu_data;
409
410 gk20a_dbg_info("");
411
412 status = boardobj_pmudatainit_super(g, board_obj_ptr, ppmudata);
413 if (status != 0)
414 return status;
415
416 pfll_dev = (struct fll_device *)board_obj_ptr;
417 perf_pmu_data = (struct nv_pmu_clk_clk_fll_device_boardobj_set *)
418 ppmudata;
419
420 perf_pmu_data->id = pfll_dev->id;
421 perf_pmu_data->mdiv = pfll_dev->mdiv;
422 perf_pmu_data->rail_idx_for_lut = pfll_dev->rail_idx_for_lut;
423 perf_pmu_data->input_freq_mhz = pfll_dev->input_freq_mhz;
424 perf_pmu_data->vin_idx_logic = pfll_dev->vin_idx_logic;
425 perf_pmu_data->vin_idx_sram = pfll_dev->vin_idx_sram;
426 perf_pmu_data->clk_domain = pfll_dev->clk_domain;
427 perf_pmu_data->min_freq_vfe_idx =
428 pfll_dev->min_freq_vfe_idx;
429 perf_pmu_data->freq_ctrl_idx = pfll_dev->freq_ctrl_idx;
430
431 memcpy(&perf_pmu_data->lut_device, &pfll_dev->lut_device,
432 sizeof(struct nv_pmu_clk_lut_device_desc));
433 memcpy(&perf_pmu_data->regime_desc, &pfll_dev->regime_desc,
434 sizeof(struct nv_pmu_clk_regime_desc));
435
436 status = boardobjgrpmask_export(
437 &pfll_dev->lut_prog_broadcast_slave_mask.super,
438 pfll_dev->lut_prog_broadcast_slave_mask.super.bitcount,
439 &perf_pmu_data->lut_prog_broadcast_slave_mask.super);
440
441 gk20a_dbg_info(" Done");
442
443 return status;
444}