summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/clk/clk_fll.c
diff options
context:
space:
mode:
authorVijayakumar Subbu <vsubbu@nvidia.com>2016-07-30 13:44:30 -0400
committerDeepak Nibade <dnibade@nvidia.com>2016-12-27 04:56:49 -0500
commit432017248e432df0619dc2df30f915a52634338f (patch)
tree40bb7a77983fb2753271bc46b346a44ebd6121cf /drivers/gpu/nvgpu/clk/clk_fll.c
parent38ad90b4840434df4650c617a236e1b01f8a43c6 (diff)
gpu: nvgpu: Add dGPU clocks support
JIRA DNVGPU-42 Change-Id: Ic2fca9d0cf82f2823654ac5e8f0772a1eec7b3b5 Signed-off-by: Vijayakumar Subbu <vsubbu@nvidia.com> Signed-off-by: Terje Bergstrom <tbergstrom@nvidia.com> Reviewed-on: http://git-master/r/1205850 (cherry picked from commit b9f5c6bc4e649162d63e33d65b725872340ca114) Reviewed-on: http://git-master/r/1227257 GVS: Gerrit_Virtual_Submit
Diffstat (limited to 'drivers/gpu/nvgpu/clk/clk_fll.c')
-rw-r--r--drivers/gpu/nvgpu/clk/clk_fll.c440
1 files changed, 440 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..0de857f5
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk_fll.c
@@ -0,0 +1,440 @@
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 "clk.h"
16#include "clk_fll.h"
17#include "include/bios.h"
18#include "boardobj/boardobjgrp.h"
19#include "boardobj/boardobjgrp_e32.h"
20#include "pmuif/gpmuifboardobj.h"
21#include "pmuif/gpmuifclk.h"
22#include "gm206/bios_gm206.h"
23#include "ctrl/ctrlclk.h"
24#include "ctrl/ctrlvolt.h"
25#include "gk20a/pmu_gk20a.h"
26
27static u32 devinit_get_fll_device_table(struct gk20a *g,
28 struct avfsfllobjs *pfllobjs);
29static struct fll_device *construct_fll_device(struct gk20a *g,
30 void *pargs);
31static u32 fll_device_init_pmudata_super(struct gk20a *g,
32 struct boardobj *board_obj_ptr,
33 struct nv_pmu_boardobj *ppmudata);
34
35static u32 _clk_fll_devgrp_pmudatainit_super(struct gk20a *g,
36 struct boardobjgrp *pboardobjgrp,
37 struct nv_pmu_boardobjgrp_super *pboardobjgrppmu)
38{
39 struct nv_pmu_clk_clk_fll_device_boardobjgrp_set_header *pset =
40 (struct nv_pmu_clk_clk_fll_device_boardobjgrp_set_header *)
41 pboardobjgrppmu;
42 struct avfsfllobjs *pfll_objs = (struct avfsfllobjs *)
43 pboardobjgrp;
44 u32 status = 0;
45
46 gk20a_dbg_info("");
47
48 status = boardobjgrp_pmudatainit_e32(g, pboardobjgrp, pboardobjgrppmu);
49 if (status) {
50 gk20a_err(dev_from_gk20a(g), "failed to init fll pmuobjgrp");
51 return status;
52 }
53 pset->lut_num_entries = pfll_objs->lut_num_entries;
54 pset->lut_step_size_uv = pfll_objs->lut_step_size_uv;
55 pset->lut_min_voltage_uv = pfll_objs->lut_min_voltage_uv;
56 pset->max_min_freq_mhz = pfll_objs->max_min_freq_mhz;
57
58 status = boardobjgrpmask_export(
59 &pfll_objs->lut_prog_master_mask.super,
60 pfll_objs->lut_prog_master_mask.super.bitcount,
61 &pset->lut_prog_master_mask.super);
62
63 gk20a_dbg_info(" Done");
64 return status;
65}
66
67static u32 _clk_fll_devgrp_pmudata_instget(struct gk20a *g,
68 struct nv_pmu_boardobjgrp *pmuboardobjgrp,
69 struct nv_pmu_boardobj **ppboardobjpmudata,
70 u8 idx)
71{
72 struct nv_pmu_clk_clk_fll_device_boardobj_grp_set *pgrp_set =
73 (struct nv_pmu_clk_clk_fll_device_boardobj_grp_set *)
74 pmuboardobjgrp;
75
76 gk20a_dbg_info("");
77
78 /*check whether pmuboardobjgrp has a valid boardobj in index*/
79 if (((u32)BIT(idx) &
80 pgrp_set->hdr.data.super.obj_mask.super.data[0]) == 0)
81 return -EINVAL;
82
83 *ppboardobjpmudata = (struct nv_pmu_boardobj *)
84 &pgrp_set->objects[idx].data.board_obj;
85 gk20a_dbg_info(" Done");
86 return 0;
87}
88
89static u32 _clk_fll_devgrp_pmustatus_instget(struct gk20a *g,
90 void *pboardobjgrppmu,
91 struct nv_pmu_boardobj_query **ppboardobjpmustatus,
92 u8 idx)
93{
94 struct nv_pmu_clk_clk_fll_device_boardobj_grp_get_status *pgrp_get_status =
95 (struct nv_pmu_clk_clk_fll_device_boardobj_grp_get_status *)
96 pboardobjgrppmu;
97
98 /*check whether pmuboardobjgrp has a valid boardobj in index*/
99 if (((u32)BIT(idx) &
100 pgrp_get_status->hdr.data.super.obj_mask.super.data[0]) == 0)
101 return -EINVAL;
102
103 *ppboardobjpmustatus = (struct nv_pmu_boardobj_query *)
104 &pgrp_get_status->objects[idx].data.board_obj;
105 return 0;
106}
107
108u32 clk_fll_sw_setup(struct gk20a *g)
109{
110 u32 status;
111 struct boardobjgrp *pboardobjgrp = NULL;
112 struct avfsfllobjs *pfllobjs;
113 struct fll_device *pfll;
114 struct fll_device *pfll_master;
115 struct fll_device *pfll_local;
116 u8 i;
117 u8 j;
118
119 gk20a_dbg_info("");
120
121 status = boardobjgrpconstruct_e32(&g->clk_pmu.avfs_fllobjs.super);
122 if (status) {
123 gk20a_err(dev_from_gk20a(g),
124 "error creating boardobjgrp for fll, status - 0x%x", status);
125 goto done;
126 }
127 pfllobjs = &(g->clk_pmu.avfs_fllobjs);
128 pboardobjgrp = &(g->clk_pmu.avfs_fllobjs.super.super);
129
130 BOARDOBJGRP_PMU_CONSTRUCT(pboardobjgrp, CLK, FLL_DEVICE);
131
132 status = BOARDOBJGRP_PMU_CMD_GRP_SET_CONSTRUCT(g, pboardobjgrp,
133 clk, CLK, clk_fll_device, CLK_FLL_DEVICE);
134 if (status) {
135 gk20a_err(dev_from_gk20a(g),
136 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
137 status);
138 goto done;
139 }
140
141 pboardobjgrp->pmudatainit = _clk_fll_devgrp_pmudatainit_super;
142 pboardobjgrp->pmudatainstget = _clk_fll_devgrp_pmudata_instget;
143 pboardobjgrp->pmustatusinstget = _clk_fll_devgrp_pmustatus_instget;
144 pfllobjs = (struct avfsfllobjs *)pboardobjgrp;
145 pfllobjs->lut_num_entries = CTRL_CLK_LUT_NUM_ENTRIES;
146 pfllobjs->lut_step_size_uv = CTRL_CLK_VIN_STEP_SIZE_UV;
147 pfllobjs->lut_min_voltage_uv = CTRL_CLK_LUT_MIN_VOLTAGE_UV;
148
149 /* Initialize lut prog master mask to zero.*/
150 boardobjgrpmask_e32_init(&pfllobjs->lut_prog_master_mask, NULL);
151
152 status = devinit_get_fll_device_table(g, pfllobjs);
153 if (status)
154 goto done;
155
156 status = BOARDOBJGRP_PMU_CMD_GRP_GET_STATUS_CONSTRUCT(g,
157 &g->clk_pmu.avfs_fllobjs.super.super,
158 clk, CLK, clk_fll_device, CLK_FLL_DEVICE);
159 if (status) {
160 gk20a_err(dev_from_gk20a(g),
161 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
162 status);
163 goto done;
164 }
165
166 BOARDOBJGRP_FOR_EACH(&(pfllobjs->super.super),
167 struct fll_device *, pfll, i) {
168 pfll_master = NULL;
169 j = 0;
170 BOARDOBJGRP_ITERATOR(&(pfllobjs->super.super),
171 struct fll_device *, pfll_local, j,
172 &pfllobjs->lut_prog_master_mask.super) {
173 if (pfll_local->clk_domain == pfll->clk_domain) {
174 pfll_master = pfll_local;
175 break;
176 }
177 }
178
179 if (pfll_master == NULL) {
180 status = boardobjgrpmask_bitset(
181 &pfllobjs->lut_prog_master_mask.super,
182 BOARDOBJ_GET_IDX(pfll));
183 if (status) {
184 gk20a_err(dev_from_gk20a(g), "err setting lutprogmask");
185 goto done;
186 }
187 pfll_master = pfll;
188 }
189 status = pfll_master->lut_broadcast_slave_register(
190 g, pfllobjs, pfll_master, pfll);
191
192 if (status) {
193 gk20a_err(dev_from_gk20a(g), "err setting lutslavemask");
194 goto done;
195 }
196 }
197done:
198 gk20a_dbg_info(" done status %x", status);
199 return status;
200}
201
202u32 clk_fll_pmu_setup(struct gk20a *g)
203{
204 u32 status;
205 struct boardobjgrp *pboardobjgrp = NULL;
206
207 gk20a_dbg_info("");
208
209 pboardobjgrp = &g->clk_pmu.avfs_fllobjs.super.super;
210
211 if (!pboardobjgrp->bconstructed)
212 return -EINVAL;
213
214 status = pboardobjgrp->pmuinithandle(g, pboardobjgrp);
215
216 gk20a_dbg_info("Done");
217 return status;
218}
219
220static u32 devinit_get_fll_device_table(struct gk20a *g,
221 struct avfsfllobjs *pfllobjs)
222{
223 u32 status = 0;
224 u8 *fll_table_ptr = NULL;
225 struct fll_descriptor_header fll_desc_table_header_sz = { 0 };
226 struct fll_descriptor_header_10 fll_desc_table_header = { 0 };
227 struct fll_descriptor_entry_10 fll_desc_table_entry = { 0 };
228 u8 *fll_tbl_entry_ptr = NULL;
229 u32 index = 0;
230 struct fll_device fll_dev_data;
231 struct fll_device *pfll_dev;
232 struct vin_device *pvin_dev;
233 u32 desctablesize;
234 u32 vbios_domain = NV_PERF_DOMAIN_4X_CLOCK_DOMAIN_SKIP;
235 struct avfsvinobjs *pvinobjs = &g->clk_pmu.avfs_vinobjs;
236
237 gk20a_dbg_info("");
238
239 if (g->ops.bios.get_perf_table_ptrs) {
240 fll_table_ptr = (u8 *)g->ops.bios.get_perf_table_ptrs(g,
241 g->bios.clock_token, FLL_TABLE);
242 if (fll_table_ptr == NULL) {
243 status = -1;
244 goto done;
245 }
246 }
247
248 memcpy(&fll_desc_table_header_sz, fll_table_ptr,
249 sizeof(struct fll_descriptor_header));
250 if (fll_desc_table_header_sz.size >= FLL_DESCRIPTOR_HEADER_10_SIZE_6)
251 desctablesize = FLL_DESCRIPTOR_HEADER_10_SIZE_6;
252 else
253 desctablesize = FLL_DESCRIPTOR_HEADER_10_SIZE_4;
254
255 memcpy(&fll_desc_table_header, fll_table_ptr, desctablesize);
256
257 if (desctablesize == FLL_DESCRIPTOR_HEADER_10_SIZE_6)
258 pfllobjs->max_min_freq_mhz =
259 fll_desc_table_header.max_min_freq_mhz;
260 else
261 pfllobjs->max_min_freq_mhz = 0;
262
263 /* Read table entries*/
264 fll_tbl_entry_ptr = fll_table_ptr + desctablesize;
265 for (index = 0; index < fll_desc_table_header.entry_count; index++) {
266 u32 fll_id;
267
268 memcpy(&fll_desc_table_entry, fll_tbl_entry_ptr,
269 sizeof(struct fll_descriptor_entry_10));
270
271 if (fll_desc_table_entry.fll_device_type == CTRL_CLK_FLL_TYPE_DISABLED)
272 continue;
273
274 fll_id = fll_desc_table_entry.fll_device_id;
275
276 pvin_dev = CLK_GET_VIN_DEVICE(pvinobjs,
277 (u8)fll_desc_table_entry.vin_idx_logic);
278 if (pvin_dev == NULL)
279 return -EINVAL;
280
281 pvin_dev->flls_shared_mask |= BIT(fll_id);
282
283 pvin_dev = CLK_GET_VIN_DEVICE(pvinobjs,
284 (u8)fll_desc_table_entry.vin_idx_sram);
285 if (pvin_dev == NULL)
286 return -EINVAL;
287
288 pvin_dev->flls_shared_mask |= BIT(fll_id);
289
290 fll_dev_data.super.type =
291 (u8)fll_desc_table_entry.fll_device_type;
292 fll_dev_data.id = (u8)fll_desc_table_entry.fll_device_id;
293 fll_dev_data.mdiv = (u8)BIOS_GET_FIELD(
294 fll_desc_table_entry.fll_params,
295 NV_FLL_DESC_FLL_PARAMS_MDIV);
296 fll_dev_data.input_freq_mhz =
297 (u16)fll_desc_table_entry.ref_freq_mhz;
298 fll_dev_data.min_freq_vfe_idx =
299 (u8)fll_desc_table_entry.min_freq_vfe_idx;
300 fll_dev_data.freq_ctrl_idx = CTRL_BOARDOBJ_IDX_INVALID;
301
302 vbios_domain = (u32)(fll_desc_table_entry.clk_domain &
303 NV_PERF_DOMAIN_4X_CLOCK_DOMAIN_MASK);
304 if (vbios_domain == 0)
305 fll_dev_data.clk_domain = CTRL_CLK_DOMAIN_GPC2CLK;
306 else if (vbios_domain == 1)
307 fll_dev_data.clk_domain = CTRL_CLK_DOMAIN_XBAR2CLK;
308 else if (vbios_domain == 3)
309 fll_dev_data.clk_domain = CTRL_CLK_DOMAIN_SYS2CLK;
310 else
311 continue;
312
313 fll_dev_data.rail_idx_for_lut = 0;
314
315 fll_dev_data.vin_idx_logic =
316 (u8)fll_desc_table_entry.vin_idx_logic;
317 fll_dev_data.vin_idx_sram =
318 (u8)fll_desc_table_entry.vin_idx_sram;
319 fll_dev_data.lut_device.vselect_mode =
320 (u8)BIOS_GET_FIELD(fll_desc_table_entry.lut_params,
321 NV_FLL_DESC_LUT_PARAMS_VSELECT);
322 fll_dev_data.lut_device.hysteresis_threshold =
323 (u8)BIOS_GET_FIELD(fll_desc_table_entry.lut_params,
324 NV_FLL_DESC_LUT_PARAMS_HYSTERISIS_THRESHOLD);
325 fll_dev_data.regime_desc.regime_id =
326 CTRL_CLK_FLL_REGIME_ID_FFR;
327 fll_dev_data.regime_desc.fixed_freq_regime_limit_mhz =
328 (u16)fll_desc_table_entry.ffr_cutoff_freq_mhz;
329
330 /*construct fll device*/
331 pfll_dev = construct_fll_device(g, (void *)&fll_dev_data);
332
333 status = boardobjgrp_objinsert(&pfllobjs->super.super,
334 (struct boardobj *)pfll_dev, index);
335
336 fll_tbl_entry_ptr += fll_desc_table_header.entry_size;
337 }
338
339done:
340 gk20a_dbg_info(" done status %x", status);
341 return status;
342}
343
344static u32 lutbroadcastslaveregister(struct gk20a *g,
345 struct avfsfllobjs *pfllobjs,
346 struct fll_device *pfll,
347 struct fll_device *pfll_slave)
348{
349 if (pfll->clk_domain != pfll_slave->clk_domain)
350 return -EINVAL;
351
352 return boardobjgrpmask_bitset(&pfll->
353 lut_prog_broadcast_slave_mask.super,
354 BOARDOBJ_GET_IDX(pfll_slave));
355}
356
357static struct fll_device *construct_fll_device(struct gk20a *g,
358 void *pargs)
359{
360 struct boardobj *board_obj_ptr = NULL;
361 struct fll_device *pfll_dev;
362 struct fll_device *board_obj_fll_ptr = NULL;
363 u32 status;
364
365 gk20a_dbg_info("");
366 status = boardobj_construct_super(g, &board_obj_ptr,
367 sizeof(struct fll_device), pargs);
368 if (status)
369 return NULL;
370
371 pfll_dev = (struct fll_device *)pargs;
372 board_obj_fll_ptr = (struct fll_device *)board_obj_ptr;
373 board_obj_ptr->pmudatainit = fll_device_init_pmudata_super;
374 board_obj_fll_ptr->lut_broadcast_slave_register =
375 lutbroadcastslaveregister;
376 board_obj_fll_ptr->id = pfll_dev->id;
377 board_obj_fll_ptr->mdiv = pfll_dev->mdiv;
378 board_obj_fll_ptr->rail_idx_for_lut = pfll_dev->rail_idx_for_lut;
379 board_obj_fll_ptr->input_freq_mhz = pfll_dev->input_freq_mhz;
380 board_obj_fll_ptr->clk_domain = pfll_dev->clk_domain;
381 board_obj_fll_ptr->vin_idx_logic = pfll_dev->vin_idx_logic;
382 board_obj_fll_ptr->vin_idx_sram = pfll_dev->vin_idx_sram;
383 board_obj_fll_ptr->min_freq_vfe_idx =
384 pfll_dev->min_freq_vfe_idx;
385 board_obj_fll_ptr->freq_ctrl_idx = pfll_dev->freq_ctrl_idx;
386 memcpy(&board_obj_fll_ptr->lut_device, &pfll_dev->lut_device,
387 sizeof(struct nv_pmu_clk_lut_device_desc));
388 memcpy(&board_obj_fll_ptr->regime_desc, &pfll_dev->regime_desc,
389 sizeof(struct nv_pmu_clk_regime_desc));
390 boardobjgrpmask_e32_init(
391 &board_obj_fll_ptr->lut_prog_broadcast_slave_mask, NULL);
392
393 gk20a_dbg_info(" Done");
394
395 return (struct fll_device *)board_obj_ptr;
396}
397
398static u32 fll_device_init_pmudata_super(struct gk20a *g,
399 struct boardobj *board_obj_ptr,
400 struct nv_pmu_boardobj *ppmudata)
401{
402 u32 status = 0;
403 struct fll_device *pfll_dev;
404 struct nv_pmu_clk_clk_fll_device_boardobj_set *perf_pmu_data;
405
406 gk20a_dbg_info("");
407
408 status = boardobj_pmudatainit_super(g, board_obj_ptr, ppmudata);
409 if (status != 0)
410 return status;
411
412 pfll_dev = (struct fll_device *)board_obj_ptr;
413 perf_pmu_data = (struct nv_pmu_clk_clk_fll_device_boardobj_set *)
414 ppmudata;
415
416 perf_pmu_data->id = pfll_dev->id;
417 perf_pmu_data->mdiv = pfll_dev->mdiv;
418 perf_pmu_data->rail_idx_for_lut = pfll_dev->rail_idx_for_lut;
419 perf_pmu_data->input_freq_mhz = pfll_dev->input_freq_mhz;
420 perf_pmu_data->vin_idx_logic = pfll_dev->vin_idx_logic;
421 perf_pmu_data->vin_idx_sram = pfll_dev->vin_idx_sram;
422 perf_pmu_data->clk_domain = pfll_dev->clk_domain;
423 perf_pmu_data->min_freq_vfe_idx =
424 pfll_dev->min_freq_vfe_idx;
425 perf_pmu_data->freq_ctrl_idx = pfll_dev->freq_ctrl_idx;
426
427 memcpy(&perf_pmu_data->lut_device, &pfll_dev->lut_device,
428 sizeof(struct nv_pmu_clk_lut_device_desc));
429 memcpy(&perf_pmu_data->regime_desc, &pfll_dev->regime_desc,
430 sizeof(struct nv_pmu_clk_regime_desc));
431
432 status = boardobjgrpmask_export(
433 &pfll_dev->lut_prog_broadcast_slave_mask.super,
434 pfll_dev->lut_prog_broadcast_slave_mask.super.bitcount,
435 &perf_pmu_data->lut_prog_broadcast_slave_mask.super);
436
437 gk20a_dbg_info(" Done");
438
439 return status;
440}