summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/clk
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
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')
-rw-r--r--drivers/gpu/nvgpu/clk/clk.c190
-rw-r--r--drivers/gpu/nvgpu/clk/clk.h86
-rw-r--r--drivers/gpu/nvgpu/clk/clk_domain.c874
-rw-r--r--drivers/gpu/nvgpu/clk/clk_domain.h94
-rw-r--r--drivers/gpu/nvgpu/clk/clk_fll.c440
-rw-r--r--drivers/gpu/nvgpu/clk/clk_fll.h68
-rw-r--r--drivers/gpu/nvgpu/clk/clk_prog.c834
-rw-r--r--drivers/gpu/nvgpu/clk/clk_prog.h71
-rw-r--r--drivers/gpu/nvgpu/clk/clk_vf_point.c347
-rw-r--r--drivers/gpu/nvgpu/clk/clk_vf_point.h74
-rw-r--r--drivers/gpu/nvgpu/clk/clk_vin.c466
-rw-r--r--drivers/gpu/nvgpu/clk/clk_vin.h56
12 files changed, 3600 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/clk/clk.c b/drivers/gpu/nvgpu/clk/clk.c
new file mode 100644
index 00000000..0679efc0
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk.c
@@ -0,0 +1,190 @@
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 "pmuif/gpmuifclk.h"
17#include "pmuif/gpmuifvolt.h"
18#include "ctrl/ctrlclk.h"
19#include "ctrl/ctrlvolt.h"
20#include "gk20a/pmu_gk20a.h"
21
22struct clkrpc_pmucmdhandler_params {
23 struct nv_pmu_clk_rpc *prpccall;
24 u32 success;
25};
26
27static void clkrpc_pmucmdhandler(struct gk20a *g, struct pmu_msg *msg,
28 void *param, u32 handle, u32 status)
29{
30 struct clkrpc_pmucmdhandler_params *phandlerparams =
31 (struct clkrpc_pmucmdhandler_params *)param;
32
33 gk20a_dbg_info("");
34
35 if (msg->msg.clk.msg_type != NV_PMU_CLK_MSG_ID_RPC) {
36 gk20a_err(dev_from_gk20a(g),
37 "unsupported msg for VFE LOAD RPC %x",
38 msg->msg.clk.msg_type);
39 return;
40 }
41
42 if (phandlerparams->prpccall->b_supported)
43 phandlerparams->success = 1;
44}
45
46u32 clk_pmu_vin_load(struct gk20a *g)
47{
48 struct pmu_cmd cmd;
49 struct pmu_msg msg;
50 struct pmu_payload payload = { {0} };
51 u32 status;
52 u32 seqdesc;
53 struct nv_pmu_clk_rpc rpccall = {0};
54 struct clkrpc_pmucmdhandler_params handler = {0};
55 struct nv_pmu_clk_load *clkload;
56
57 rpccall.function = NV_PMU_CLK_RPC_ID_LOAD;
58 clkload = &rpccall.params.clk_load;
59 clkload->feature = NV_NV_PMU_CLK_LOAD_FEATURE_VIN;
60 clkload->action_mask = NV_NV_PMU_CLK_LOAD_ACTION_MASK_VIN_HW_CAL_PROGRAM_YES << 4;
61
62 cmd.hdr.unit_id = PMU_UNIT_CLK;
63 cmd.hdr.size = (u32)sizeof(struct nv_pmu_clk_cmd) +
64 (u32)sizeof(struct pmu_hdr);
65
66 cmd.cmd.clk.cmd_type = NV_PMU_CLK_CMD_ID_RPC;
67 msg.hdr.size = sizeof(struct pmu_msg);
68
69 payload.in.buf = (u8 *)&rpccall;
70 payload.in.size = (u32)sizeof(struct nv_pmu_clk_rpc);
71 payload.in.fb_size = PMU_CMD_SUBMIT_PAYLOAD_PARAMS_FB_SIZE_UNUSED;
72 payload.in.offset = NV_PMU_CLK_CMD_RPC_ALLOC_OFFSET;
73
74 payload.out.buf = (u8 *)&rpccall;
75 payload.out.size = (u32)sizeof(struct nv_pmu_clk_rpc);
76 payload.out.fb_size = PMU_CMD_SUBMIT_PAYLOAD_PARAMS_FB_SIZE_UNUSED;
77 payload.out.offset = NV_PMU_CLK_MSG_RPC_ALLOC_OFFSET;
78
79 handler.prpccall = &rpccall;
80 handler.success = 0;
81
82 status = gk20a_pmu_cmd_post(g, &cmd, NULL, &payload,
83 PMU_COMMAND_QUEUE_LPQ,
84 clkrpc_pmucmdhandler, (void *)&handler,
85 &seqdesc, ~0);
86
87 if (status) {
88 gk20a_err(dev_from_gk20a(g),
89 "unable to post clk RPC cmd %x",
90 cmd.cmd.clk.cmd_type);
91 goto done;
92 }
93
94 pmu_wait_message_cond(&g->pmu,
95 gk20a_get_gr_idle_timeout(g),
96 &handler.success, 1);
97
98 if (handler.success == 0) {
99 gk20a_err(dev_from_gk20a(g), "rpc call to load vin cal failed");
100 status = -EINVAL;
101 }
102
103done:
104 return status;
105}
106
107u32 clk_pmu_vf_inject(struct gk20a *g)
108{
109 struct pmu_cmd cmd;
110 struct pmu_msg msg;
111 struct pmu_payload payload = { {0} };
112 u32 status;
113 u32 seqdesc;
114 struct nv_pmu_clk_rpc rpccall = {0};
115 struct clkrpc_pmucmdhandler_params handler = {0};
116 struct nv_pmu_clk_vf_change_inject *vfchange;
117
118 rpccall.function = NV_PMU_CLK_RPC_ID_CLK_VF_CHANGE_INJECT;
119 vfchange = &rpccall.params.clk_vf_change_inject;
120 vfchange->flags = 0;
121 vfchange->clk_list.num_domains = 3;
122 vfchange->clk_list.clk_domains[0].clk_domain = CTRL_CLK_DOMAIN_GPC2CLK;
123 vfchange->clk_list.clk_domains[0].clk_freq_khz = 2581 * 1000;
124 vfchange->clk_list.clk_domains[0].clk_flags = 0;
125 vfchange->clk_list.clk_domains[0].current_regime_id =
126 CTRL_CLK_FLL_REGIME_ID_FFR;
127 vfchange->clk_list.clk_domains[0].target_regime_id =
128 CTRL_CLK_FLL_REGIME_ID_FR;
129 vfchange->clk_list.clk_domains[1].clk_domain = CTRL_CLK_DOMAIN_XBAR2CLK;
130 vfchange->clk_list.clk_domains[1].clk_freq_khz = 2505 * 1000;
131 vfchange->clk_list.clk_domains[1].clk_flags = 0;
132 vfchange->clk_list.clk_domains[1].current_regime_id =
133 CTRL_CLK_FLL_REGIME_ID_FFR;
134 vfchange->clk_list.clk_domains[1].target_regime_id =
135 CTRL_CLK_FLL_REGIME_ID_FR;
136 vfchange->clk_list.clk_domains[2].clk_domain = CTRL_CLK_DOMAIN_SYS2CLK;
137 vfchange->clk_list.clk_domains[2].clk_freq_khz = 2328 * 1000;
138 vfchange->clk_list.clk_domains[2].clk_flags = 0;
139 vfchange->clk_list.clk_domains[2].current_regime_id =
140 CTRL_CLK_FLL_REGIME_ID_FFR;
141 vfchange->clk_list.clk_domains[2].target_regime_id =
142 CTRL_CLK_FLL_REGIME_ID_FR;
143 vfchange->volt_list.num_rails = 1;
144 vfchange->volt_list.rails[0].volt_domain = CTRL_VOLT_DOMAIN_LOGIC;
145 vfchange->volt_list.rails[0].voltage_uv = 825000;
146 vfchange->volt_list.rails[0].voltage_min_noise_unaware_uv = 825000;
147
148 cmd.hdr.unit_id = PMU_UNIT_CLK;
149 cmd.hdr.size = (u32)sizeof(struct nv_pmu_clk_cmd) +
150 (u32)sizeof(struct pmu_hdr);
151
152 cmd.cmd.clk.cmd_type = NV_PMU_CLK_CMD_ID_RPC;
153 msg.hdr.size = sizeof(struct pmu_msg);
154
155 payload.in.buf = (u8 *)&rpccall;
156 payload.in.size = (u32)sizeof(struct nv_pmu_clk_rpc);
157 payload.in.fb_size = PMU_CMD_SUBMIT_PAYLOAD_PARAMS_FB_SIZE_UNUSED;
158 payload.in.offset = NV_PMU_CLK_CMD_RPC_ALLOC_OFFSET;
159
160 payload.out.buf = (u8 *)&rpccall;
161 payload.out.size = (u32)sizeof(struct nv_pmu_clk_rpc);
162 payload.out.fb_size = PMU_CMD_SUBMIT_PAYLOAD_PARAMS_FB_SIZE_UNUSED;
163 payload.out.offset = NV_PMU_CLK_MSG_RPC_ALLOC_OFFSET;
164
165 handler.prpccall = &rpccall;
166 handler.success = 0;
167
168 status = gk20a_pmu_cmd_post(g, &cmd, NULL, &payload,
169 PMU_COMMAND_QUEUE_LPQ,
170 clkrpc_pmucmdhandler, (void *)&handler,
171 &seqdesc, ~0);
172
173 if (status) {
174 gk20a_err(dev_from_gk20a(g),
175 "unable to post clk RPC cmd %x",
176 cmd.cmd.clk.cmd_type);
177 goto done;
178 }
179
180 pmu_wait_message_cond(&g->pmu,
181 gk20a_get_gr_idle_timeout(g),
182 &handler.success, 1);
183
184 if (handler.success == 0) {
185 gk20a_err(dev_from_gk20a(g), "rpc call to inject clock failed");
186 status = -EINVAL;
187 }
188done:
189 return status;
190}
diff --git a/drivers/gpu/nvgpu/clk/clk.h b/drivers/gpu/nvgpu/clk/clk.h
new file mode 100644
index 00000000..d638424f
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk.h
@@ -0,0 +1,86 @@
1/*
2 * general clock structures & definitions
3 *
4 * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 */
15#ifndef _CLK_H_
16#define _CLK_H_
17
18#include "clk_vin.h"
19#include "clk_fll.h"
20#include "clk_domain.h"
21#include "clk_prog.h"
22#include "clk_vf_point.h"
23#include "gk20a/gk20a.h"
24
25#define NV_PERF_DOMAIN_4X_CLOCK_DOMAIN_SKIP 0x10
26#define NV_PERF_DOMAIN_4X_CLOCK_DOMAIN_MASK 0x1F
27#define NV_PERF_DOMAIN_4X_CLOCK_DOMAIN_SHIFT 0
28
29/* clock related defines for GPUs supporting clock control from pmu*/
30struct clk_pmupstate {
31 struct avfsvinobjs avfs_vinobjs;
32 struct avfsfllobjs avfs_fllobjs;
33 struct clk_domains clk_domainobjs;
34 struct clk_progs clk_progobjs;
35 struct clk_vf_points clk_vf_pointobjs;
36};
37
38struct clockentry {
39 u8 vbios_clk_domain;
40 u8 clk_which;
41 u8 perf_index;
42 u32 api_clk_domain;
43};
44
45#define NV_PERF_HEADER_4X_CLOCKS_DOMAINS_MAX_NUMCLKS 9
46
47struct vbios_clock_domain {
48 u8 clock_type;
49 u8 num_domains;
50 struct clockentry clock_entry[NV_PERF_HEADER_4X_CLOCKS_DOMAINS_MAX_NUMCLKS];
51};
52
53struct vbios_clocks_table_1x_hal_clock_entry {
54 enum nv_pmu_clk_clkwhich domain;
55 bool b_noise_aware_capable;
56};
57
58#define NV_PERF_HEADER_4X_CLOCKS_DOMAINS_4_GPC2CLK 0
59#define NV_PERF_HEADER_4X_CLOCKS_DOMAINS_4_XBAR2CLK 1
60#define NV_PERF_HEADER_4X_CLOCKS_DOMAINS_4_DRAMCLK 2
61#define NV_PERF_HEADER_4X_CLOCKS_DOMAINS_4_SYS2CLK 3
62#define NV_PERF_HEADER_4X_CLOCKS_DOMAINS_4_HUB2CLK 4
63#define NV_PERF_HEADER_4X_CLOCKS_DOMAINS_4_MSDCLK 5
64#define NV_PERF_HEADER_4X_CLOCKS_DOMAINS_4_PWRCLK 6
65#define NV_PERF_HEADER_4X_CLOCKS_DOMAINS_4_DISPCLK 7
66#define NV_PERF_HEADER_4X_CLOCKS_DOMAINS_4_NUMCLKS 8
67
68#define PERF_CLK_MCLK 0
69#define PERF_CLK_DISPCLK 1
70#define PERF_CLK_GPC2CLK 2
71#define PERF_CLK_HOSTCLK 3
72#define PERF_CLK_LTC2CLK 4
73#define PERF_CLK_SYS2CLK 5
74#define PERF_CLK_HUB2CLK 6
75#define PERF_CLK_LEGCLK 7
76#define PERF_CLK_MSDCLK 8
77#define PERF_CLK_XCLK 9
78#define PERF_CLK_PWRCLK 10
79#define PERF_CLK_XBAR2CLK 11
80#define PERF_CLK_PCIEGENCLK 12
81#define PERF_CLK_NUM 13
82
83u32 clk_pmu_vf_inject(struct gk20a *g);
84u32 clk_pmu_vin_load(struct gk20a *g);
85
86#endif
diff --git a/drivers/gpu/nvgpu/clk/clk_domain.c b/drivers/gpu/nvgpu/clk/clk_domain.c
new file mode 100644
index 00000000..dc485e6b
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk_domain.c
@@ -0,0 +1,874 @@
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 "clk_domain.h"
18#include "include/bios.h"
19#include "boardobj/boardobjgrp.h"
20#include "boardobj/boardobjgrp_e32.h"
21#include "pmuif/gpmuifboardobj.h"
22#include "pmuif/gpmuifclk.h"
23#include "gm206/bios_gm206.h"
24#include "ctrl/ctrlclk.h"
25#include "ctrl/ctrlvolt.h"
26#include "gk20a/pmu_gk20a.h"
27
28static struct clk_domain *construct_clk_domain(struct gk20a *g, void *pargs);
29
30static u32 devinit_get_clocks_table(struct gk20a *g,
31 struct clk_domains *pdomainobjs);
32
33static u32 clk_domain_pmudatainit_super(struct gk20a *g, struct boardobj
34 *board_obj_ptr, struct nv_pmu_boardobj *ppmudata);
35
36const struct vbios_clocks_table_1x_hal_clock_entry vbiosclktbl1xhalentry[] = {
37 { clkwhich_gpc2clk, true, },
38 { clkwhich_xbar2clk, true, },
39 { clkwhich_mclk, false, },
40 { clkwhich_sys2clk, true, },
41 { clkwhich_hub2clk, false, },
42 { clkwhich_nvdclk, false, },
43 { clkwhich_pwrclk, false, },
44 { clkwhich_dispclk, false, },
45 { clkwhich_pciegenclk, false, }
46};
47
48static u32 clktranslatehalmumsettoapinumset(u32 clkhaldomains)
49{
50 u32 clkapidomains = 0;
51
52 if (clkhaldomains & BIT(clkwhich_gpc2clk))
53 clkapidomains |= CTRL_CLK_DOMAIN_GPC2CLK;
54 if (clkhaldomains & BIT(clkwhich_xbar2clk))
55 clkapidomains |= CTRL_CLK_DOMAIN_XBAR2CLK;
56 if (clkhaldomains & BIT(clkwhich_sys2clk))
57 clkapidomains |= CTRL_CLK_DOMAIN_SYS2CLK;
58 if (clkhaldomains & BIT(clkwhich_hub2clk))
59 clkapidomains |= CTRL_CLK_DOMAIN_HUB2CLK;
60 if (clkhaldomains & BIT(clkwhich_pwrclk))
61 clkapidomains |= CTRL_CLK_DOMAIN_PWRCLK;
62 if (clkhaldomains & BIT(clkwhich_pciegenclk))
63 clkapidomains |= CTRL_CLK_DOMAIN_PCIEGENCLK;
64 if (clkhaldomains & BIT(clkwhich_mclk))
65 clkapidomains |= CTRL_CLK_DOMAIN_MCLK;
66 if (clkhaldomains & BIT(clkwhich_nvdclk))
67 clkapidomains |= CTRL_CLK_DOMAIN_NVDCLK;
68 if (clkhaldomains & BIT(clkwhich_dispclk))
69 clkapidomains |= CTRL_CLK_DOMAIN_DISPCLK;
70
71 return clkapidomains;
72}
73
74static u32 _clk_domains_pmudatainit_3x(struct gk20a *g,
75 struct boardobjgrp *pboardobjgrp,
76 struct nv_pmu_boardobjgrp_super *pboardobjgrppmu)
77{
78 struct nv_pmu_clk_clk_domain_boardobjgrp_set_header *pset =
79 (struct nv_pmu_clk_clk_domain_boardobjgrp_set_header *)
80 pboardobjgrppmu;
81 struct clk_domains *pdomains = (struct clk_domains *)pboardobjgrp;
82 u32 status = 0;
83
84 status = boardobjgrp_pmudatainit_e32(g, pboardobjgrp, pboardobjgrppmu);
85 if (status) {
86 gk20a_err(dev_from_gk20a(g),
87 "error updating pmu boardobjgrp for clk domain 0x%x",
88 status);
89 goto done;
90 }
91
92 pset->vbios_domains = pdomains->vbios_domains;
93 pset->cntr_sampling_periodms = pdomains->cntr_sampling_periodms;
94 pset->b_override_o_v_o_c = false;
95 pset->b_debug_mode = false;
96 pset->b_enforce_vf_monotonicity = pdomains->b_enforce_vf_monotonicity;
97 pset->volt_rails_max = 2;
98 status = boardobjgrpmask_export(
99 &pdomains->master_domains_mask.super,
100 pdomains->master_domains_mask.super.bitcount,
101 &pset->master_domains_mask.super);
102
103 memcpy(&pset->deltas, &pdomains->deltas,
104 (sizeof(struct ctrl_clk_clk_delta)));
105
106done:
107 return status;
108}
109
110static u32 _clk_domains_pmudata_instget(struct gk20a *g,
111 struct nv_pmu_boardobjgrp *pmuboardobjgrp,
112 struct nv_pmu_boardobj **ppboardobjpmudata,
113 u8 idx)
114{
115 struct nv_pmu_clk_clk_domain_boardobj_grp_set *pgrp_set =
116 (struct nv_pmu_clk_clk_domain_boardobj_grp_set *)
117 pmuboardobjgrp;
118
119 gk20a_dbg_info("");
120
121 /*check whether pmuboardobjgrp has a valid boardobj in index*/
122 if (((u32)BIT(idx) &
123 pgrp_set->hdr.data.super.obj_mask.super.data[0]) == 0)
124 return -EINVAL;
125
126 *ppboardobjpmudata = (struct nv_pmu_boardobj *)
127 &pgrp_set->objects[idx].data.board_obj;
128 gk20a_dbg_info(" Done");
129 return 0;
130}
131
132u32 clk_domain_sw_setup(struct gk20a *g)
133{
134 u32 status;
135 struct boardobjgrp *pboardobjgrp = NULL;
136 struct clk_domains *pclkdomainobjs;
137 struct clk_domain *pdomain;
138 u8 i;
139
140 gk20a_dbg_info("");
141
142 status = boardobjgrpconstruct_e32(&g->clk_pmu.clk_domainobjs.super);
143 if (status) {
144 gk20a_err(dev_from_gk20a(g),
145 "error creating boardobjgrp for clk domain, status - 0x%x",
146 status);
147 goto done;
148 }
149
150 pboardobjgrp = &g->clk_pmu.clk_domainobjs.super.super;
151 pclkdomainobjs = &(g->clk_pmu.clk_domainobjs);
152
153 BOARDOBJGRP_PMU_CONSTRUCT(pboardobjgrp, CLK, CLK_DOMAIN);
154
155 status = BOARDOBJGRP_PMU_CMD_GRP_SET_CONSTRUCT(g, pboardobjgrp,
156 clk, CLK, clk_domain, CLK_DOMAIN);
157 if (status) {
158 gk20a_err(dev_from_gk20a(g),
159 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
160 status);
161 goto done;
162 }
163
164 pboardobjgrp->pmudatainit = _clk_domains_pmudatainit_3x;
165 pboardobjgrp->pmudatainstget = _clk_domains_pmudata_instget;
166
167 /* Initialize mask to zero.*/
168 boardobjgrpmask_e32_init(&pclkdomainobjs->prog_domains_mask, NULL);
169 boardobjgrpmask_e32_init(&pclkdomainobjs->master_domains_mask, NULL);
170 pclkdomainobjs->b_enforce_vf_monotonicity = true;
171
172 memset(&pclkdomainobjs->ordered_noise_aware_list, 0,
173 sizeof(pclkdomainobjs->ordered_noise_aware_list));
174
175 memset(&pclkdomainobjs->ordered_noise_unaware_list, 0,
176 sizeof(pclkdomainobjs->ordered_noise_unaware_list));
177
178 memset(&pclkdomainobjs->deltas, 0,
179 sizeof(struct ctrl_clk_clk_delta));
180
181 status = devinit_get_clocks_table(g, pclkdomainobjs);
182 if (status)
183 goto done;
184
185 BOARDOBJGRP_FOR_EACH(&(pclkdomainobjs->super.super),
186 struct clk_domain *, pdomain, i) {
187 if (pdomain->super.implements(g, &pdomain->super,
188 CTRL_CLK_CLK_DOMAIN_TYPE_3X_PROG)) {
189 status = boardobjgrpmask_bitset(
190 &pclkdomainobjs->prog_domains_mask.super, i);
191 if (status)
192 goto done;
193 }
194
195 if (pdomain->super.implements(g, &pdomain->super,
196 CTRL_CLK_CLK_DOMAIN_TYPE_3X_MASTER)) {
197 status = boardobjgrpmask_bitset(
198 &pclkdomainobjs->master_domains_mask.super, i);
199 if (status)
200 goto done;
201 }
202 }
203
204done:
205 gk20a_dbg_info(" done status %x", status);
206 return status;
207}
208
209u32 clk_domain_pmu_setup(struct gk20a *g)
210{
211 u32 status;
212 struct boardobjgrp *pboardobjgrp = NULL;
213
214 gk20a_dbg_info("");
215
216 pboardobjgrp = &g->clk_pmu.clk_domainobjs.super.super;
217
218 if (!pboardobjgrp->bconstructed)
219 return -EINVAL;
220
221 status = pboardobjgrp->pmuinithandle(g, pboardobjgrp);
222
223 gk20a_dbg_info("Done");
224 return status;
225}
226
227static u32 devinit_get_clocks_table(struct gk20a *g,
228 struct clk_domains *pclkdomainobjs)
229{
230 u32 status = 0;
231 u8 *clocks_table_ptr = NULL;
232 struct vbios_clocks_table_1x_header clocks_table_header = { 0 };
233 struct vbios_clocks_table_1x_entry clocks_table_entry = { 0 };
234 u8 *clocks_tbl_entry_ptr = NULL;
235 u32 index = 0;
236 struct clk_domain *pclkdomain_dev;
237 union {
238 struct boardobj boardobj;
239 struct clk_domain clk_domain;
240 struct clk_domain_3x v3x;
241 struct clk_domain_3x_fixed v3x_fixed;
242 struct clk_domain_3x_prog v3x_prog;
243 struct clk_domain_3x_master v3x_master;
244 struct clk_domain_3x_slave v3x_slave;
245 } clk_domain_data;
246
247 gk20a_dbg_info("");
248
249 if (g->ops.bios.get_perf_table_ptrs) {
250 clocks_table_ptr = (u8 *)g->ops.bios.get_perf_table_ptrs(g,
251 g->bios.clock_token, CLOCKS_TABLE);
252 if (clocks_table_ptr == NULL) {
253 status = -EINVAL;
254 goto done;
255 }
256 }
257
258 memcpy(&clocks_table_header, clocks_table_ptr,
259 VBIOS_CLOCKS_TABLE_1X_HEADER_SIZE_07);
260 if (clocks_table_header.header_size <
261 VBIOS_CLOCKS_TABLE_1X_HEADER_SIZE_07) {
262 status = -EINVAL;
263 goto done;
264 }
265
266 if (clocks_table_header.entry_size <
267 VBIOS_CLOCKS_TABLE_1X_ENTRY_SIZE_09) {
268 status = -EINVAL;
269 goto done;
270 }
271
272 pclkdomainobjs->cntr_sampling_periodms =
273 (u16)clocks_table_header.cntr_sampling_periodms;
274
275 /* Read table entries*/
276 clocks_tbl_entry_ptr = clocks_table_ptr +
277 VBIOS_CLOCKS_TABLE_1X_HEADER_SIZE_07;
278 for (index = 0; index < clocks_table_header.entry_count; index++) {
279 memcpy(&clocks_table_entry, clocks_tbl_entry_ptr,
280 clocks_table_header.entry_size);
281 clk_domain_data.clk_domain.domain =
282 vbiosclktbl1xhalentry[index].domain;
283 clk_domain_data.clk_domain.api_domain =
284 clktranslatehalmumsettoapinumset(
285 BIT(clk_domain_data.clk_domain.domain));
286 clk_domain_data.v3x.b_noise_aware_capable =
287 vbiosclktbl1xhalentry[index].b_noise_aware_capable;
288
289 switch (BIOS_GET_FIELD(clocks_table_entry.flags0,
290 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_FLAGS0_USAGE)) {
291 case NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_FLAGS0_USAGE_FIXED:
292 clk_domain_data.boardobj.type =
293 CTRL_CLK_CLK_DOMAIN_TYPE_3X_FIXED;
294 clk_domain_data.v3x_fixed.freq_mhz = (u16)BIOS_GET_FIELD(
295 clocks_table_entry.param1,
296 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM1_FIXED_FREQUENCY_MHZ);
297 break;
298
299 case NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_FLAGS0_USAGE_MASTER:
300 clk_domain_data.boardobj.type =
301 CTRL_CLK_CLK_DOMAIN_TYPE_3X_MASTER;
302 clk_domain_data.v3x_prog.clk_prog_idx_first =
303 (u8)(BIOS_GET_FIELD(clocks_table_entry.param0,
304 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM0_PROG_CLK_PROG_IDX_FIRST));
305 clk_domain_data.v3x_prog.clk_prog_idx_last =
306 (u8)(BIOS_GET_FIELD(clocks_table_entry.param0,
307 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM0_PROG_CLK_PROG_IDX_LAST));
308 clk_domain_data.v3x_prog.noise_unaware_ordering_index =
309 (u8)(BIOS_GET_FIELD(clocks_table_entry.param2,
310 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM2_PROG_NOISE_UNAWARE_ORDERING_IDX));
311
312 if (clk_domain_data.v3x.b_noise_aware_capable) {
313 clk_domain_data.v3x_prog.noise_aware_ordering_index =
314 (u8)(BIOS_GET_FIELD(clocks_table_entry.param2,
315 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM2_PROG_NOISE_AWARE_ORDERING_IDX));
316 clk_domain_data.v3x_prog.b_force_noise_unaware_ordering =
317 (u8)(BIOS_GET_FIELD(clocks_table_entry.param2,
318 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM2_PROG_FORCE_NOISE_UNAWARE_ORDERING));
319 } else {
320 clk_domain_data.v3x_prog.noise_aware_ordering_index =
321 CTRL_CLK_CLK_DOMAIN_3X_PROG_ORDERING_INDEX_INVALID;
322 clk_domain_data.v3x_prog.b_force_noise_unaware_ordering = false;
323 }
324 clk_domain_data.v3x_prog.factory_offset_khz = 0;
325
326 clk_domain_data.v3x_prog.freq_delta_min_mhz =
327 (u16)(BIOS_GET_FIELD(clocks_table_entry.param1,
328 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM1_MASTER_FREQ_OC_DELTA_MIN_MHZ));
329
330 clk_domain_data.v3x_prog.freq_delta_max_mhz =
331 (u16)(BIOS_GET_FIELD(clocks_table_entry.param1,
332 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM1_MASTER_FREQ_OC_DELTA_MAX_MHZ));
333 break;
334
335 case NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_FLAGS0_USAGE_SLAVE:
336 clk_domain_data.boardobj.type =
337 CTRL_CLK_CLK_DOMAIN_TYPE_3X_SLAVE;
338 clk_domain_data.v3x_prog.clk_prog_idx_first =
339 (u8)(BIOS_GET_FIELD(clocks_table_entry.param0,
340 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM0_PROG_CLK_PROG_IDX_FIRST));
341 clk_domain_data.v3x_prog.clk_prog_idx_last =
342 (u8)(BIOS_GET_FIELD(clocks_table_entry.param0,
343 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM0_PROG_CLK_PROG_IDX_LAST));
344 clk_domain_data.v3x_prog.noise_unaware_ordering_index =
345 (u8)(BIOS_GET_FIELD(clocks_table_entry.param2,
346 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM2_PROG_NOISE_UNAWARE_ORDERING_IDX));
347
348 if (clk_domain_data.v3x.b_noise_aware_capable) {
349 clk_domain_data.v3x_prog.noise_aware_ordering_index =
350 (u8)(BIOS_GET_FIELD(clocks_table_entry.param2,
351 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM2_PROG_NOISE_AWARE_ORDERING_IDX));
352 clk_domain_data.v3x_prog.b_force_noise_unaware_ordering =
353 (u8)(BIOS_GET_FIELD(clocks_table_entry.param2,
354 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM2_PROG_FORCE_NOISE_UNAWARE_ORDERING));
355 } else {
356 clk_domain_data.v3x_prog.noise_aware_ordering_index =
357 CTRL_CLK_CLK_DOMAIN_3X_PROG_ORDERING_INDEX_INVALID;
358 clk_domain_data.v3x_prog.b_force_noise_unaware_ordering = false;
359 }
360 clk_domain_data.v3x_prog.factory_offset_khz = 0;
361 clk_domain_data.v3x_prog.freq_delta_min_mhz = 0;
362 clk_domain_data.v3x_prog.freq_delta_max_mhz = 0;
363 clk_domain_data.v3x_slave.master_idx =
364 (u8)(BIOS_GET_FIELD(clocks_table_entry.param1,
365 NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM1_SLAVE_MASTER_DOMAIN));
366 break;
367
368 default:
369 gk20a_err(dev_from_gk20a(g),
370 "error reading clock domain entry %d", index);
371 status = -EINVAL;
372 goto done;
373
374 }
375 pclkdomain_dev = construct_clk_domain(g,
376 (void *)&clk_domain_data);
377 if (pclkdomain_dev == NULL) {
378 gk20a_err(dev_from_gk20a(g),
379 "unable to construct clock domain boardobj for %d",
380 index);
381 status = -EINVAL;
382 goto done;
383 }
384 status = boardobjgrp_objinsert(&pclkdomainobjs->super.super,
385 (struct boardobj *)pclkdomain_dev, index);
386 if (status) {
387 gk20a_err(dev_from_gk20a(g),
388 "unable to insert clock domain boardobj for %d", index);
389 status = -EINVAL;
390 goto done;
391 }
392 clocks_tbl_entry_ptr += clocks_table_header.entry_size;
393 }
394
395done:
396 gk20a_dbg_info(" done status %x", status);
397 return status;
398}
399
400static u32 clkdomainclkproglink_not_supported(struct gk20a *g,
401 struct clk_pmupstate *pclk,
402 struct clk_domain *pdomain)
403{
404 gk20a_dbg_info("");
405 return -EINVAL;
406}
407
408static u32 clk_domain_construct_super(struct gk20a *g,
409 struct boardobj **ppboardobj,
410 u16 size, void *pargs)
411{
412 struct clk_domain *pdomain;
413 struct clk_domain *ptmpdomain = (struct clk_domain *)pargs;
414 u32 status = 0;
415
416 status = boardobj_construct_super(g, ppboardobj,
417 size, pargs);
418
419 if (status)
420 return -EINVAL;
421
422 pdomain = (struct clk_domain *)*ppboardobj;
423
424 pdomain->super.pmudatainit =
425 clk_domain_pmudatainit_super;
426
427 pdomain->clkdomainclkproglink =
428 clkdomainclkproglink_not_supported;
429
430 pdomain->api_domain = ptmpdomain->api_domain;
431 pdomain->domain = ptmpdomain->domain;
432 pdomain->perf_domain_grp_idx =
433 ptmpdomain->perf_domain_grp_idx;
434
435 return status;
436}
437
438static u32 _clk_domain_pmudatainit_3x(struct gk20a *g,
439 struct boardobj *board_obj_ptr,
440 struct nv_pmu_boardobj *ppmudata)
441{
442 u32 status = 0;
443 struct clk_domain_3x *pclk_domain_3x;
444 struct nv_pmu_clk_clk_domain_3x_boardobj_set *pset;
445
446 gk20a_dbg_info("");
447
448 status = clk_domain_pmudatainit_super(g, board_obj_ptr, ppmudata);
449 if (status != 0)
450 return status;
451
452 pclk_domain_3x = (struct clk_domain_3x *)board_obj_ptr;
453
454 pset = (struct nv_pmu_clk_clk_domain_3x_boardobj_set *)ppmudata;
455
456 pset->b_noise_aware_capable = pclk_domain_3x->b_noise_aware_capable;
457
458 return status;
459}
460
461static u32 clk_domain_construct_3x(struct gk20a *g,
462 struct boardobj **ppboardobj,
463 u16 size, void *pargs)
464{
465 struct boardobj *ptmpobj = (struct boardobj *)pargs;
466 struct clk_domain_3x *pdomain;
467 struct clk_domain_3x *ptmpdomain =
468 (struct clk_domain_3x *)pargs;
469 u32 status = 0;
470
471 ptmpobj->type_mask = BIT(CTRL_CLK_CLK_DOMAIN_TYPE_3X);
472 status = clk_domain_construct_super(g, ppboardobj,
473 size, pargs);
474 if (status)
475 return -EINVAL;
476
477 pdomain = (struct clk_domain_3x *)*ppboardobj;
478
479 pdomain->super.super.pmudatainit =
480 _clk_domain_pmudatainit_3x;
481
482 pdomain->b_noise_aware_capable = ptmpdomain->b_noise_aware_capable;
483
484 return status;
485}
486
487static u32 clkdomainclkproglink_3x_prog(struct gk20a *g,
488 struct clk_pmupstate *pclk,
489 struct clk_domain *pdomain)
490{
491 u32 status = 0;
492 struct clk_domain_3x_prog *p3xprog =
493 (struct clk_domain_3x_prog *)pdomain;
494 struct clk_prog *pprog = NULL;
495 u8 i;
496
497 gk20a_dbg_info("");
498
499 for (i = p3xprog->clk_prog_idx_first;
500 i <= p3xprog->clk_prog_idx_last;
501 i++) {
502 pprog = CLK_CLK_PROG_GET(pclk, i);
503 if (pprog == NULL)
504 status = -EINVAL;
505 }
506 return status;
507}
508
509static u32 _clk_domain_pmudatainit_3x_prog(struct gk20a *g,
510 struct boardobj *board_obj_ptr,
511 struct nv_pmu_boardobj *ppmudata)
512{
513 u32 status = 0;
514 struct clk_domain_3x_prog *pclk_domain_3x_prog;
515 struct nv_pmu_clk_clk_domain_3x_prog_boardobj_set *pset;
516 struct clk_domains *pdomains = &(g->clk_pmu.clk_domainobjs);
517
518 gk20a_dbg_info("");
519
520 status = _clk_domain_pmudatainit_3x(g, board_obj_ptr, ppmudata);
521 if (status != 0)
522 return status;
523
524 pclk_domain_3x_prog = (struct clk_domain_3x_prog *)board_obj_ptr;
525
526 pset = (struct nv_pmu_clk_clk_domain_3x_prog_boardobj_set *)
527 ppmudata;
528
529 pset->clk_prog_idx_first = pclk_domain_3x_prog->clk_prog_idx_first;
530 pset->clk_prog_idx_last = pclk_domain_3x_prog->clk_prog_idx_last;
531 pset->noise_unaware_ordering_index =
532 pclk_domain_3x_prog->noise_unaware_ordering_index;
533 pset->noise_aware_ordering_index =
534 pclk_domain_3x_prog->noise_aware_ordering_index;
535 pset->b_force_noise_unaware_ordering =
536 pclk_domain_3x_prog->b_force_noise_unaware_ordering;
537 pset->factory_offset_khz = pclk_domain_3x_prog->factory_offset_khz;
538 pset->freq_delta_min_mhz = pclk_domain_3x_prog->freq_delta_min_mhz;
539 pset->freq_delta_max_mhz = pclk_domain_3x_prog->freq_delta_max_mhz;
540 memcpy(&pset->deltas, &pdomains->deltas,
541 (sizeof(struct ctrl_clk_clk_delta)));
542
543 return status;
544}
545
546static u32 clk_domain_construct_3x_prog(struct gk20a *g,
547 struct boardobj **ppboardobj,
548 u16 size, void *pargs)
549{
550 struct boardobj *ptmpobj = (struct boardobj *)pargs;
551 struct clk_domain_3x_prog *pdomain;
552 struct clk_domain_3x_prog *ptmpdomain =
553 (struct clk_domain_3x_prog *)pargs;
554 u32 status = 0;
555
556 ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_DOMAIN_TYPE_3X_PROG);
557 status = clk_domain_construct_3x(g, ppboardobj, size, pargs);
558 if (status)
559 return -EINVAL;
560
561 pdomain = (struct clk_domain_3x_prog *)*ppboardobj;
562
563 pdomain->super.super.super.pmudatainit =
564 _clk_domain_pmudatainit_3x_prog;
565
566 pdomain->super.super.clkdomainclkproglink =
567 clkdomainclkproglink_3x_prog;
568
569 pdomain->clk_prog_idx_first = ptmpdomain->clk_prog_idx_first;
570 pdomain->clk_prog_idx_last = ptmpdomain->clk_prog_idx_last;
571 pdomain->noise_unaware_ordering_index =
572 ptmpdomain->noise_unaware_ordering_index;
573 pdomain->noise_aware_ordering_index =
574 ptmpdomain->noise_aware_ordering_index;
575 pdomain->b_force_noise_unaware_ordering =
576 ptmpdomain->b_force_noise_unaware_ordering;
577 pdomain->factory_offset_khz = ptmpdomain->factory_offset_khz;
578 pdomain->freq_delta_min_mhz = ptmpdomain->freq_delta_min_mhz;
579 pdomain->freq_delta_max_mhz = ptmpdomain->freq_delta_max_mhz;
580
581 return status;
582}
583
584static u32 _clk_domain_pmudatainit_3x_slave(struct gk20a *g,
585 struct boardobj *board_obj_ptr,
586 struct nv_pmu_boardobj *ppmudata)
587{
588 u32 status = 0;
589 struct clk_domain_3x_slave *pclk_domain_3x_slave;
590 struct nv_pmu_clk_clk_domain_3x_slave_boardobj_set *pset;
591
592 gk20a_dbg_info("");
593
594 status = _clk_domain_pmudatainit_3x_prog(g, board_obj_ptr, ppmudata);
595 if (status != 0)
596 return status;
597
598 pclk_domain_3x_slave = (struct clk_domain_3x_slave *)board_obj_ptr;
599
600 pset = (struct nv_pmu_clk_clk_domain_3x_slave_boardobj_set *)
601 ppmudata;
602
603 pset->master_idx = pclk_domain_3x_slave->master_idx;
604
605 return status;
606}
607
608static u32 clk_domain_construct_3x_slave(struct gk20a *g,
609 struct boardobj **ppboardobj,
610 u16 size, void *pargs)
611{
612 struct boardobj *ptmpobj = (struct boardobj *)pargs;
613 struct clk_domain_3x_slave *pdomain;
614 struct clk_domain_3x_slave *ptmpdomain =
615 (struct clk_domain_3x_slave *)pargs;
616 u32 status = 0;
617
618 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_CLK_CLK_DOMAIN_TYPE_3X_SLAVE)
619 return -EINVAL;
620
621 ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_DOMAIN_TYPE_3X_SLAVE);
622 status = clk_domain_construct_3x_prog(g, ppboardobj, size, pargs);
623 if (status)
624 return -EINVAL;
625
626 pdomain = (struct clk_domain_3x_slave *)*ppboardobj;
627
628 pdomain->super.super.super.super.pmudatainit =
629 _clk_domain_pmudatainit_3x_slave;
630
631 pdomain->master_idx = ptmpdomain->master_idx;
632
633 return status;
634}
635
636static u32 clkdomainclkproglink_3x_master(struct gk20a *g,
637 struct clk_pmupstate *pclk,
638 struct clk_domain *pdomain)
639{
640 u32 status = 0;
641 struct clk_domain_3x_master *p3xmaster =
642 (struct clk_domain_3x_master *)pdomain;
643 struct clk_prog *pprog = NULL;
644 struct clk_prog_1x_master *pprog1xmaster = NULL;
645 u16 freq_max_last_mhz = 0;
646 u8 i;
647
648 gk20a_dbg_info("");
649
650 status = clkdomainclkproglink_3x_prog(g, pclk, pdomain);
651 if (status)
652 goto done;
653
654 /* Iterate over the set of CLK_PROGs pointed at by this domain.*/
655 for (i = p3xmaster->super.clk_prog_idx_first;
656 i <= p3xmaster->super.clk_prog_idx_last;
657 i++) {
658 pprog = CLK_CLK_PROG_GET(pclk, i);
659
660 /* MASTER CLK_DOMAINs must point to MASTER CLK_PROGs.*/
661 if (!pprog->super.implements(g, &pprog->super,
662 CTRL_CLK_CLK_PROG_TYPE_1X_MASTER)) {
663 status = -EINVAL;
664 goto done;
665 }
666
667 pprog1xmaster = (struct clk_prog_1x_master *)pprog;
668 status = pprog1xmaster->vfflatten(g, pclk, pprog1xmaster,
669 BOARDOBJ_GET_IDX(p3xmaster), &freq_max_last_mhz);
670 if (status)
671 goto done;
672 }
673done:
674 gk20a_dbg_info("done status %x", status);
675 return status;
676}
677
678static u32 _clk_domain_pmudatainit_3x_master(struct gk20a *g,
679 struct boardobj *board_obj_ptr,
680 struct nv_pmu_boardobj *ppmudata)
681{
682 u32 status = 0;
683 struct clk_domain_3x_master *pclk_domain_3x_master;
684 struct nv_pmu_clk_clk_domain_3x_master_boardobj_set *pset;
685
686 gk20a_dbg_info("");
687
688 status = _clk_domain_pmudatainit_3x_prog(g, board_obj_ptr, ppmudata);
689 if (status != 0)
690 return status;
691
692 pclk_domain_3x_master = (struct clk_domain_3x_master *)board_obj_ptr;
693
694 pset = (struct nv_pmu_clk_clk_domain_3x_master_boardobj_set *)
695 ppmudata;
696
697 pset->slave_idxs_mask = pclk_domain_3x_master->slave_idxs_mask;
698
699 return status;
700}
701
702static u32 clk_domain_construct_3x_master(struct gk20a *g,
703 struct boardobj **ppboardobj,
704 u16 size, void *pargs)
705{
706 struct boardobj *ptmpobj = (struct boardobj *)pargs;
707 struct clk_domain_3x_master *pdomain;
708 struct clk_domain_3x_master *ptmpdomain =
709 (struct clk_domain_3x_master *)pargs;
710 u32 status = 0;
711
712 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_CLK_CLK_DOMAIN_TYPE_3X_MASTER)
713 return -EINVAL;
714
715 ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_DOMAIN_TYPE_3X_MASTER);
716 status = clk_domain_construct_3x_prog(g, ppboardobj, size, pargs);
717 if (status)
718 return -EINVAL;
719
720 pdomain = (struct clk_domain_3x_master *)*ppboardobj;
721
722 pdomain->super.super.super.super.pmudatainit =
723 _clk_domain_pmudatainit_3x_master;
724 pdomain->super.super.super.clkdomainclkproglink =
725 clkdomainclkproglink_3x_master;
726
727 pdomain->slave_idxs_mask = ptmpdomain->slave_idxs_mask;
728
729 return status;
730}
731
732static u32 clkdomainclkproglink_fixed(struct gk20a *g,
733 struct clk_pmupstate *pclk,
734 struct clk_domain *pdomain)
735{
736 gk20a_dbg_info("");
737 return 0;
738}
739
740static u32 _clk_domain_pmudatainit_3x_fixed(struct gk20a *g,
741 struct boardobj *board_obj_ptr,
742 struct nv_pmu_boardobj *ppmudata)
743{
744 u32 status = 0;
745 struct clk_domain_3x_fixed *pclk_domain_3x_fixed;
746 struct nv_pmu_clk_clk_domain_3x_fixed_boardobj_set *pset;
747
748 gk20a_dbg_info("");
749
750 status = _clk_domain_pmudatainit_3x(g, board_obj_ptr, ppmudata);
751 if (status != 0)
752 return status;
753
754 pclk_domain_3x_fixed = (struct clk_domain_3x_fixed *)board_obj_ptr;
755
756 pset = (struct nv_pmu_clk_clk_domain_3x_fixed_boardobj_set *)
757 ppmudata;
758
759 pset->freq_mhz = pclk_domain_3x_fixed->freq_mhz;
760
761 return status;
762}
763
764static u32 clk_domain_construct_3x_fixed(struct gk20a *g,
765 struct boardobj **ppboardobj,
766 u16 size, void *pargs)
767{
768 struct boardobj *ptmpobj = (struct boardobj *)pargs;
769 struct clk_domain_3x_fixed *pdomain;
770 struct clk_domain_3x_fixed *ptmpdomain =
771 (struct clk_domain_3x_fixed *)pargs;
772 u32 status = 0;
773
774 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_CLK_CLK_DOMAIN_TYPE_3X_FIXED)
775 return -EINVAL;
776
777 ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_DOMAIN_TYPE_3X_FIXED);
778 status = clk_domain_construct_3x(g, ppboardobj, size, pargs);
779 if (status)
780 return -EINVAL;
781
782 pdomain = (struct clk_domain_3x_fixed *)*ppboardobj;
783
784 pdomain->super.super.super.pmudatainit =
785 _clk_domain_pmudatainit_3x_fixed;
786
787 pdomain->super.super.clkdomainclkproglink =
788 clkdomainclkproglink_fixed;
789
790 pdomain->freq_mhz = ptmpdomain->freq_mhz;
791
792 return status;
793}
794
795static struct clk_domain *construct_clk_domain(struct gk20a *g, void *pargs)
796{
797 struct boardobj *board_obj_ptr = NULL;
798 u32 status;
799
800 gk20a_dbg_info(" %d", BOARDOBJ_GET_TYPE(pargs));
801 switch (BOARDOBJ_GET_TYPE(pargs)) {
802 case CTRL_CLK_CLK_DOMAIN_TYPE_3X_FIXED:
803 status = clk_domain_construct_3x_fixed(g, &board_obj_ptr,
804 sizeof(struct clk_domain_3x_fixed), pargs);
805 break;
806
807 case CTRL_CLK_CLK_DOMAIN_TYPE_3X_MASTER:
808 status = clk_domain_construct_3x_master(g, &board_obj_ptr,
809 sizeof(struct clk_domain_3x_master), pargs);
810 break;
811
812 case CTRL_CLK_CLK_DOMAIN_TYPE_3X_SLAVE:
813 status = clk_domain_construct_3x_slave(g, &board_obj_ptr,
814 sizeof(struct clk_domain_3x_slave), pargs);
815 break;
816
817 default:
818 return NULL;
819 }
820
821 if (status)
822 return NULL;
823
824 gk20a_dbg_info(" Done");
825
826 return (struct clk_domain *)board_obj_ptr;
827}
828
829static u32 clk_domain_pmudatainit_super(struct gk20a *g,
830 struct boardobj *board_obj_ptr,
831 struct nv_pmu_boardobj *ppmudata)
832{
833 u32 status = 0;
834 struct clk_domain *pclk_domain;
835 struct nv_pmu_clk_clk_domain_boardobj_set *pset;
836
837 gk20a_dbg_info("");
838
839 status = boardobj_pmudatainit_super(g, board_obj_ptr, ppmudata);
840 if (status != 0)
841 return status;
842
843 pclk_domain = (struct clk_domain *)board_obj_ptr;
844
845 pset = (struct nv_pmu_clk_clk_domain_boardobj_set *)ppmudata;
846
847 pset->domain = pclk_domain->domain;
848 pset->api_domain = pclk_domain->api_domain;
849 pset->perf_domain_grp_idx = pclk_domain->perf_domain_grp_idx;
850
851 return status;
852}
853
854u32 clk_domain_clk_prog_link(struct gk20a *g, struct clk_pmupstate *pclk)
855{
856 u32 status = 0;
857 struct clk_domain *pdomain;
858 u8 i;
859
860 /* Iterate over all CLK_DOMAINs and flatten their VF curves.*/
861 BOARDOBJGRP_FOR_EACH(&(pclk->clk_domainobjs.super.super),
862 struct clk_domain *, pdomain, i) {
863 status = pdomain->clkdomainclkproglink(g, pclk, pdomain);
864 if (status) {
865 gk20a_err(dev_from_gk20a(g),
866 "error flattening VF for CLK DOMAIN - 0x%x",
867 pdomain->domain);
868 goto done;
869 }
870 }
871
872done:
873 return status;
874}
diff --git a/drivers/gpu/nvgpu/clk/clk_domain.h b/drivers/gpu/nvgpu/clk/clk_domain.h
new file mode 100644
index 00000000..94d612a7
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk_domain.h
@@ -0,0 +1,94 @@
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#ifndef _CLKDOMAIN_H_
15#define _CLKDOMAIN_H_
16
17#include "ctrl/ctrlclk.h"
18#include "ctrl/ctrlboardobj.h"
19#include "pmuif/gpmuifclk.h"
20#include "boardobj/boardobjgrp_e32.h"
21#include "boardobj/boardobjgrpmask.h"
22
23struct clk_domains;
24struct clk_domain;
25
26/*data and function definition to talk to driver*/
27u32 clk_domain_sw_setup(struct gk20a *g);
28u32 clk_domain_pmu_setup(struct gk20a *g);
29typedef u32 clkproglink(struct gk20a *g, struct clk_pmupstate *pclk,
30 struct clk_domain *pdomain);
31struct clk_domains {
32 struct boardobjgrp_e32 super;
33 u8 n_num_entries;
34 u8 version;
35 bool b_enforce_vf_monotonicity;
36 u32 vbios_domains;
37 struct boardobjgrpmask_e32 prog_domains_mask;
38 struct boardobjgrpmask_e32 master_domains_mask;
39 u16 cntr_sampling_periodms;
40 struct ctrl_clk_clk_delta deltas;
41
42 struct clk_domain *ordered_noise_aware_list[CTRL_BOARDOBJ_MAX_BOARD_OBJECTS];
43
44 struct clk_domain *ordered_noise_unaware_list[CTRL_BOARDOBJ_MAX_BOARD_OBJECTS];
45};
46
47struct clk_domain {
48 struct boardobj super;
49 u32 api_domain;
50 u32 part_mask;
51 u8 domain;
52 u8 perf_domain_index;
53 u8 perf_domain_grp_idx;
54 u8 ratio_domain;
55 u8 usage;
56 clkproglink *clkdomainclkproglink;
57};
58
59struct clk_domain_3x {
60 struct clk_domain super;
61 bool b_noise_aware_capable;
62};
63
64struct clk_domain_3x_fixed {
65 struct clk_domain_3x super;
66 u16 freq_mhz;
67};
68
69struct clk_domain_3x_prog {
70 struct clk_domain_3x super;
71 u8 clk_prog_idx_first;
72 u8 clk_prog_idx_last;
73 u8 noise_unaware_ordering_index;
74 u8 noise_aware_ordering_index;
75 bool b_force_noise_unaware_ordering;
76 int factory_offset_khz;
77 short freq_delta_min_mhz;
78 short freq_delta_max_mhz;
79 struct ctrl_clk_clk_delta deltas;
80};
81
82struct clk_domain_3x_master {
83 struct clk_domain_3x_prog super;
84 u32 slave_idxs_mask;
85};
86
87struct clk_domain_3x_slave {
88 struct clk_domain_3x_prog super;
89 u8 master_idx;
90};
91
92u32 clk_domain_clk_prog_link(struct gk20a *g, struct clk_pmupstate *pclk);
93
94#endif
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}
diff --git a/drivers/gpu/nvgpu/clk/clk_fll.h b/drivers/gpu/nvgpu/clk/clk_fll.h
new file mode 100644
index 00000000..06872f48
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk_fll.h
@@ -0,0 +1,68 @@
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#ifndef _CLKFLL_H_
15#define _CLKFLL_H_
16
17#include "pmuif/gpmuifclk.h"
18#include "boardobj/boardobjgrp_e32.h"
19#include "boardobj/boardobjgrpmask.h"
20
21/*data and function definition to talk to driver*/
22u32 clk_fll_sw_setup(struct gk20a *g);
23u32 clk_fll_pmu_setup(struct gk20a *g);
24
25struct avfsfllobjs {
26 struct boardobjgrp_e32 super;
27 struct boardobjgrpmask_e32 lut_prog_master_mask;
28 u32 lut_step_size_uv;
29 u32 lut_min_voltage_uv;
30 u8 lut_num_entries;
31 u16 max_min_freq_mhz;
32};
33
34struct fll_device;
35
36typedef u32 fll_lut_broadcast_slave_register(struct gk20a *g,
37 struct avfsfllobjs *pfllobjs,
38 struct fll_device *pfll,
39 struct fll_device *pfll_slave);
40
41struct fll_device {
42 struct boardobj super;
43 u8 id;
44 u8 mdiv;
45 u16 input_freq_mhz;
46 u32 clk_domain;
47 u8 vin_idx_logic;
48 u8 vin_idx_sram;
49 u8 rail_idx_for_lut;
50 struct nv_pmu_clk_lut_device_desc lut_device;
51 struct nv_pmu_clk_regime_desc regime_desc;
52 u8 min_freq_vfe_idx;
53 u8 freq_ctrl_idx;
54 u8 target_regime_id_override;
55 struct boardobjgrpmask_e32 lut_prog_broadcast_slave_mask;
56 fll_lut_broadcast_slave_register *lut_broadcast_slave_register;
57};
58
59#define CLK_FLL_LUT_VF_NUM_ENTRIES(pclk) \
60 (pclk->avfs_fllobjs.lut_num_entries)
61
62#define CLK_FLL_LUT_MIN_VOLTAGE_UV(pclk) \
63 (pclk->avfs_fllobjs.lut_min_voltage_uv)
64#define CLK_FLL_LUT_STEP_SIZE_UV(pclk) \
65 (pclk->avfs_fllobjs.lut_step_size_uv)
66
67#endif
68
diff --git a/drivers/gpu/nvgpu/clk/clk_prog.c b/drivers/gpu/nvgpu/clk/clk_prog.c
new file mode 100644
index 00000000..d87581c4
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk_prog.c
@@ -0,0 +1,834 @@
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_prog.h"
17#include "clk_vf_point.h"
18#include "include/bios.h"
19#include "boardobj/boardobjgrp.h"
20#include "boardobj/boardobjgrp_e32.h"
21#include "pmuif/gpmuifboardobj.h"
22#include "pmuif/gpmuifclk.h"
23#include "gm206/bios_gm206.h"
24#include "ctrl/ctrlclk.h"
25#include "ctrl/ctrlvolt.h"
26#include "gk20a/pmu_gk20a.h"
27
28static struct clk_prog *construct_clk_prog(struct gk20a *g, void *pargs);
29static u32 devinit_get_clk_prog_table(struct gk20a *g,
30 struct clk_progs *pprogobjs);
31static vf_flatten vfflatten_prog_1x_master;
32
33static u32 _clk_progs_pmudatainit(struct gk20a *g,
34 struct boardobjgrp *pboardobjgrp,
35 struct nv_pmu_boardobjgrp_super *pboardobjgrppmu)
36{
37 struct nv_pmu_clk_clk_prog_boardobjgrp_set_header *pset =
38 (struct nv_pmu_clk_clk_prog_boardobjgrp_set_header *)
39 pboardobjgrppmu;
40 struct clk_progs *pprogs = (struct clk_progs *)pboardobjgrp;
41 u32 status = 0;
42
43 status = boardobjgrp_pmudatainit_e32(g, pboardobjgrp, pboardobjgrppmu);
44 if (status) {
45 gk20a_err(dev_from_gk20a(g),
46 "error updating pmu boardobjgrp for clk prog 0x%x",
47 status);
48 goto done;
49 }
50 pset->slave_entry_count = pprogs->slave_entry_count;
51 pset->vf_entry_count = pprogs->vf_entry_count;
52
53done:
54 return status;
55}
56
57static u32 _clk_progs_pmudata_instget(struct gk20a *g,
58 struct nv_pmu_boardobjgrp *pmuboardobjgrp,
59 struct nv_pmu_boardobj **ppboardobjpmudata,
60 u8 idx)
61{
62 struct nv_pmu_clk_clk_prog_boardobj_grp_set *pgrp_set =
63 (struct nv_pmu_clk_clk_prog_boardobj_grp_set *)pmuboardobjgrp;
64
65 gk20a_dbg_info("");
66
67 /*check whether pmuboardobjgrp has a valid boardobj in index*/
68 if (((u32)BIT(idx) &
69 pgrp_set->hdr.data.super.obj_mask.super.data[0]) == 0)
70 return -EINVAL;
71
72 *ppboardobjpmudata = (struct nv_pmu_boardobj *)
73 &pgrp_set->objects[idx].data.board_obj;
74 gk20a_dbg_info(" Done");
75 return 0;
76}
77
78u32 clk_prog_sw_setup(struct gk20a *g)
79{
80 u32 status;
81 struct boardobjgrp *pboardobjgrp = NULL;
82 struct clk_progs *pclkprogobjs;
83
84 gk20a_dbg_info("");
85
86 status = boardobjgrpconstruct_e255(&g->clk_pmu.clk_progobjs.super);
87 if (status) {
88 gk20a_err(dev_from_gk20a(g),
89 "error creating boardobjgrp for clk prog, status - 0x%x",
90 status);
91 goto done;
92 }
93
94 pboardobjgrp = &g->clk_pmu.clk_progobjs.super.super;
95 pclkprogobjs = &(g->clk_pmu.clk_progobjs);
96
97 BOARDOBJGRP_PMU_CONSTRUCT(pboardobjgrp, CLK, CLK_PROG);
98
99 status = BOARDOBJGRP_PMU_CMD_GRP_SET_CONSTRUCT(g, pboardobjgrp,
100 clk, CLK, clk_prog, CLK_PROG);
101 if (status) {
102 gk20a_err(dev_from_gk20a(g),
103 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
104 status);
105 goto done;
106 }
107
108 pboardobjgrp->pmudatainit = _clk_progs_pmudatainit;
109 pboardobjgrp->pmudatainstget = _clk_progs_pmudata_instget;
110
111 status = devinit_get_clk_prog_table(g, pclkprogobjs);
112 if (status)
113 goto done;
114
115 status = clk_domain_clk_prog_link(g, &g->clk_pmu);
116 if (status) {
117 gk20a_err(dev_from_gk20a(g),
118 "error constructing VF point board objects");
119 goto done;
120 }
121
122
123done:
124 gk20a_dbg_info(" done status %x", status);
125 return status;
126}
127
128u32 clk_prog_pmu_setup(struct gk20a *g)
129{
130 u32 status;
131 struct boardobjgrp *pboardobjgrp = NULL;
132
133 gk20a_dbg_info("");
134
135 pboardobjgrp = &g->clk_pmu.clk_progobjs.super.super;
136
137 if (!pboardobjgrp->bconstructed)
138 return -EINVAL;
139
140 status = pboardobjgrp->pmuinithandle(g, pboardobjgrp);
141
142 gk20a_dbg_info("Done");
143 return status;
144}
145
146static u32 devinit_get_clk_prog_table(struct gk20a *g,
147 struct clk_progs *pclkprogobjs)
148{
149 u32 status = 0;
150 u8 *clkprogs_tbl_ptr = NULL;
151 struct vbios_clock_programming_table_1x_header header = { 0 };
152 struct vbios_clock_programming_table_1x_entry prog = { 0 };
153 struct vbios_clock_programming_table_1x_slave_entry slaveprog = { 0 };
154 struct vbios_clock_programming_table_1x_vf_entry vfprog = { 0 };
155 u8 *entry = NULL;
156 u8 *slaveentry = NULL;
157 u8 *vfentry = NULL;
158 u32 i, j = 0;
159 struct clk_prog *pprog;
160 u8 prog_type;
161 u32 szfmt = VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_SIZE_0D;
162 u32 hszfmt = VBIOS_CLOCK_PROGRAMMING_TABLE_1X_HEADER_SIZE_08;
163 u32 slaveszfmt = VBIOS_CLOCK_PROGRAMMING_TABLE_1X_SLAVE_ENTRY_SIZE_03;
164 u32 vfszfmt = VBIOS_CLOCK_PROGRAMMING_TABLE_1X_VF_ENTRY_SIZE_02;
165 struct ctrl_clk_clk_prog_1x_master_vf_entry
166 vfentries[CTRL_CLK_CLK_PROG_1X_MASTER_VF_ENTRY_MAX_ENTRIES];
167 struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry
168 ratioslaveentries[CTRL_CLK_PROG_1X_MASTER_MAX_SLAVE_ENTRIES];
169 struct ctrl_clk_clk_prog_1x_master_table_slave_entry
170 tableslaveentries[CTRL_CLK_PROG_1X_MASTER_MAX_SLAVE_ENTRIES];
171 union {
172 struct boardobj board_obj;
173 struct clk_prog clkprog;
174 struct clk_prog_1x v1x;
175 struct clk_prog_1x_master v1x_master;
176 struct clk_prog_1x_master_ratio v1x_master_ratio;
177 struct clk_prog_1x_master_table v1x_master_table;
178 } prog_data;
179
180 gk20a_dbg_info("");
181
182 if (g->ops.bios.get_perf_table_ptrs) {
183 clkprogs_tbl_ptr = (u8 *)g->ops.bios.get_perf_table_ptrs(g,
184 g->bios.clock_token, CLOCK_PROGRAMMING_TABLE);
185 if (clkprogs_tbl_ptr == NULL) {
186 status = -EINVAL;
187 goto done;
188 }
189 }
190
191 memcpy(&header, clkprogs_tbl_ptr, hszfmt);
192 if (header.header_size < hszfmt) {
193 status = -EINVAL;
194 goto done;
195 }
196 hszfmt = header.header_size;
197
198 if (header.entry_size <= VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_SIZE_05)
199 szfmt = header.entry_size;
200 else if (header.entry_size <= VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_SIZE_0D)
201 szfmt = header.entry_size;
202 else {
203 status = -EINVAL;
204 goto done;
205 }
206
207 if (header.vf_entry_size < vfszfmt) {
208 status = -EINVAL;
209 goto done;
210 }
211 vfszfmt = header.vf_entry_size;
212 if (header.slave_entry_size < slaveszfmt) {
213 status = -EINVAL;
214 goto done;
215 }
216 slaveszfmt = header.slave_entry_size;
217 if (header.vf_entry_count > CTRL_CLK_CLK_DELTA_MAX_VOLT_RAILS) {
218 status = -EINVAL;
219 goto done;
220 }
221
222 pclkprogobjs->slave_entry_count = header.slave_entry_count;
223 pclkprogobjs->vf_entry_count = header.vf_entry_count;
224
225 for (i = 0; i < header.entry_count; i++) {
226 memset(&prog_data, 0x0, (u32)sizeof(prog_data));
227
228 /* Read table entries*/
229 entry = clkprogs_tbl_ptr + hszfmt +
230 (i * (szfmt + (header.slave_entry_count * slaveszfmt) +
231 (header.vf_entry_count * vfszfmt)));
232
233 memcpy(&prog, entry, szfmt);
234 memset(vfentries, 0xFF,
235 sizeof(struct ctrl_clk_clk_prog_1x_master_vf_entry) *
236 CTRL_CLK_CLK_PROG_1X_MASTER_VF_ENTRY_MAX_ENTRIES);
237 memset(ratioslaveentries, 0xFF,
238 sizeof(struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry) *
239 CTRL_CLK_PROG_1X_MASTER_MAX_SLAVE_ENTRIES);
240 memset(tableslaveentries, 0xFF,
241 sizeof(struct ctrl_clk_clk_prog_1x_master_table_slave_entry) *
242 CTRL_CLK_PROG_1X_MASTER_MAX_SLAVE_ENTRIES);
243 prog_type = (u8)BIOS_GET_FIELD(prog.flags0,
244 NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_SOURCE);
245
246 switch (prog_type) {
247 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_SOURCE_PLL:
248 prog_data.v1x.source = CTRL_CLK_PROG_1X_SOURCE_PLL;
249 prog_data.v1x.source_data.pll.pll_idx =
250 (u8)BIOS_GET_FIELD(prog.param0,
251 NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_PARAM0_PLL_PLL_INDEX);
252 prog_data.v1x.source_data.pll.freq_step_size_mhz =
253 (u8)BIOS_GET_FIELD(prog.param1,
254 NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_PARAM1_PLL_FREQ_STEP_SIZE);
255 break;
256
257 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_SOURCE_ONE_SOURCE:
258 prog_data.v1x.source = CTRL_CLK_PROG_1X_SOURCE_ONE_SOURCE;
259 break;
260
261 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_SOURCE_FLL:
262 prog_data.v1x.source = CTRL_CLK_PROG_1X_SOURCE_FLL;
263 break;
264
265 default:
266 gk20a_err(dev_from_gk20a(g),
267 "invalid source %d", prog_type);
268 status = -EINVAL;
269 goto done;
270 }
271
272 prog_data.v1x.freq_max_mhz = (u16)prog.freq_max_mhz;
273
274 prog_type = (u8)BIOS_GET_FIELD(prog.flags0,
275 NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE);
276
277 vfentry = entry + szfmt +
278 header.slave_entry_count * slaveszfmt;
279 slaveentry = entry + szfmt;
280 switch (prog_type) {
281 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE_MASTER_RATIO:
282 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE_MASTER_TABLE:
283 prog_data.v1x_master.b_o_c_o_v_enabled = false;
284 for (j = 0; j < header.vf_entry_count; j++) {
285 memcpy(&vfprog, vfentry, vfszfmt);
286
287 vfentries[j].vfe_idx = (u8)vfprog.vfe_idx;
288 if (CTRL_CLK_PROG_1X_SOURCE_FLL ==
289 prog_data.v1x.source) {
290 vfentries[j].gain_vfe_idx = (u8)BIOS_GET_FIELD(
291 vfprog.param0,
292 NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_VF_ENTRY_PARAM0_FLL_GAIN_VFE_IDX);
293 } else {
294 vfentries[j].gain_vfe_idx = CTRL_BOARDOBJ_IDX_INVALID;
295 }
296 vfentry += vfszfmt;
297 }
298
299 prog_data.v1x_master.p_vf_entries = vfentries;
300
301 for (j = 0; j < header.slave_entry_count; j++) {
302 memcpy(&slaveprog, slaveentry, slaveszfmt);
303
304 switch (prog_type) {
305 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE_MASTER_RATIO:
306 ratioslaveentries[j].clk_dom_idx =
307 (u8)slaveprog.clk_dom_idx;
308 ratioslaveentries[j].ratio = (u8)
309 BIOS_GET_FIELD(slaveprog.param0,
310 NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_SLAVE_ENTRY_PARAM0_MASTER_RATIO_RATIO);
311 break;
312
313 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE_MASTER_TABLE:
314 tableslaveentries[j].clk_dom_idx =
315 (u8)slaveprog.clk_dom_idx;
316 tableslaveentries[j].freq_mhz =
317 (u16)BIOS_GET_FIELD(slaveprog.param0,
318 NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_SLAVE_ENTRY_PARAM0_MASTER_TABLE_FREQ);
319 break;
320 }
321 slaveentry += slaveszfmt;
322 }
323
324 switch (prog_type) {
325 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE_MASTER_RATIO:
326 prog_data.board_obj.type = CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_RATIO;
327 prog_data.v1x_master_ratio.p_slave_entries =
328 ratioslaveentries;
329 break;
330
331 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE_MASTER_TABLE:
332 prog_data.board_obj.type = CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_TABLE;
333
334 prog_data.v1x_master_table.p_slave_entries =
335 tableslaveentries;
336 break;
337
338 }
339 break;
340
341 case NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE_SLAVE:
342 prog_data.board_obj.type = CTRL_CLK_CLK_PROG_TYPE_1X;
343 break;
344
345
346 default:
347 gk20a_err(dev_from_gk20a(g),
348 "source issue %d", prog_type);
349 status = -EINVAL;
350 goto done;
351 }
352
353 pprog = construct_clk_prog(g, (void *)&prog_data);
354 if (pprog == NULL) {
355 gk20a_err(dev_from_gk20a(g),
356 "error constructing clk_prog boardobj %d", i);
357 status = -EINVAL;
358 goto done;
359 }
360
361 status = boardobjgrp_objinsert(&pclkprogobjs->super.super,
362 (struct boardobj *)pprog, i);
363 if (status) {
364 gk20a_err(dev_from_gk20a(g),
365 "error adding clk_prog boardobj %d", i);
366 status = -EINVAL;
367 goto done;
368 }
369 }
370done:
371 gk20a_dbg_info(" done status %x", status);
372 return status;
373}
374
375static u32 _clk_prog_pmudatainit_super(struct gk20a *g,
376 struct boardobj *board_obj_ptr,
377 struct nv_pmu_boardobj *ppmudata)
378{
379 u32 status = 0;
380
381 gk20a_dbg_info("");
382
383 status = boardobj_pmudatainit_super(g, board_obj_ptr, ppmudata);
384 return status;
385}
386
387static u32 _clk_prog_pmudatainit_1x(struct gk20a *g,
388 struct boardobj *board_obj_ptr,
389 struct nv_pmu_boardobj *ppmudata)
390{
391 u32 status = 0;
392 struct clk_prog_1x *pclk_prog_1x;
393 struct nv_pmu_clk_clk_prog_1x_boardobj_set *pset;
394
395 gk20a_dbg_info("");
396
397 status = _clk_prog_pmudatainit_super(g, board_obj_ptr, ppmudata);
398 if (status != 0)
399 return status;
400
401 pclk_prog_1x = (struct clk_prog_1x *)board_obj_ptr;
402
403 pset = (struct nv_pmu_clk_clk_prog_1x_boardobj_set *)
404 ppmudata;
405
406 pset->source = pclk_prog_1x->source;
407 pset->freq_max_mhz = pclk_prog_1x->freq_max_mhz;
408 pset->source_data = pclk_prog_1x->source_data;
409
410 return status;
411}
412
413static u32 _clk_prog_pmudatainit_1x_master(struct gk20a *g,
414 struct boardobj *board_obj_ptr,
415 struct nv_pmu_boardobj *ppmudata)
416{
417 u32 status = 0;
418 struct clk_prog_1x_master *pclk_prog_1x_master;
419 struct nv_pmu_clk_clk_prog_1x_master_boardobj_set *pset;
420 u32 vfsize = sizeof(struct ctrl_clk_clk_prog_1x_master_vf_entry) *
421 g->clk_pmu.clk_progobjs.vf_entry_count;
422
423 gk20a_dbg_info("");
424
425 status = _clk_prog_pmudatainit_1x(g, board_obj_ptr, ppmudata);
426
427 pclk_prog_1x_master =
428 (struct clk_prog_1x_master *)board_obj_ptr;
429
430 pset = (struct nv_pmu_clk_clk_prog_1x_master_boardobj_set *)
431 ppmudata;
432
433 memcpy(pset->vf_entries, pclk_prog_1x_master->p_vf_entries, vfsize);
434
435 pset->b_o_c_o_v_enabled = pclk_prog_1x_master->b_o_c_o_v_enabled;
436
437 memcpy(&pset->deltas, &pclk_prog_1x_master->deltas,
438 (u32) sizeof(struct ctrl_clk_clk_delta));
439
440 return status;
441}
442
443static u32 _clk_prog_pmudatainit_1x_master_ratio(struct gk20a *g,
444 struct boardobj *board_obj_ptr,
445 struct nv_pmu_boardobj *ppmudata)
446{
447 u32 status = 0;
448 struct clk_prog_1x_master_ratio *pclk_prog_1x_master_ratio;
449 struct nv_pmu_clk_clk_prog_1x_master_ratio_boardobj_set *pset;
450 u32 slavesize = sizeof(struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry) *
451 g->clk_pmu.clk_progobjs.slave_entry_count;
452
453 gk20a_dbg_info("");
454
455 status = _clk_prog_pmudatainit_1x_master(g, board_obj_ptr, ppmudata);
456 if (status != 0)
457 return status;
458
459 pclk_prog_1x_master_ratio =
460 (struct clk_prog_1x_master_ratio *)board_obj_ptr;
461
462 pset = (struct nv_pmu_clk_clk_prog_1x_master_ratio_boardobj_set *)
463 ppmudata;
464
465 memcpy(pset->slave_entries,
466 pclk_prog_1x_master_ratio->p_slave_entries, slavesize);
467
468 return status;
469}
470
471static u32 _clk_prog_pmudatainit_1x_master_table(struct gk20a *g,
472 struct boardobj *board_obj_ptr,
473 struct nv_pmu_boardobj *ppmudata)
474{
475 u32 status = 0;
476 struct clk_prog_1x_master_table *pclk_prog_1x_master_table;
477 struct nv_pmu_clk_clk_prog_1x_master_table_boardobj_set *pset;
478 u32 slavesize = sizeof(struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry) *
479 g->clk_pmu.clk_progobjs.slave_entry_count;
480
481 gk20a_dbg_info("");
482
483 status = _clk_prog_pmudatainit_1x_master(g, board_obj_ptr, ppmudata);
484 if (status != 0)
485 return status;
486
487 pclk_prog_1x_master_table =
488 (struct clk_prog_1x_master_table *)board_obj_ptr;
489
490 pset = (struct nv_pmu_clk_clk_prog_1x_master_table_boardobj_set *)
491 ppmudata;
492 memcpy(pset->slave_entries,
493 pclk_prog_1x_master_table->p_slave_entries, slavesize);
494
495 return status;
496}
497
498static u32 _clk_prog_1x_master_rail_construct_vf_point(struct gk20a *g,
499 struct clk_pmupstate *pclk,
500 struct clk_prog_1x_master *p1xmaster,
501 struct ctrl_clk_clk_prog_1x_master_vf_entry *p_vf_rail,
502 struct clk_vf_point *p_vf_point_tmp,
503 u8 *p_vf_point_idx)
504{
505 struct clk_vf_point *p_vf_point;
506 u32 status;
507
508 gk20a_dbg_info("");
509
510 p_vf_point = construct_clk_vf_point(g, (void *)p_vf_point_tmp);
511 if (p_vf_point == NULL) {
512 status = -ENOMEM;
513 goto done;
514 }
515 status = pclk->clk_vf_pointobjs.super.super.objinsert(
516 &pclk->clk_vf_pointobjs.super.super,
517 &p_vf_point->super,
518 *p_vf_point_idx);
519 if (status)
520 goto done;
521
522 p_vf_rail->vf_point_idx_last = (*p_vf_point_idx)++;
523
524done:
525 gk20a_dbg_info("done status %x", status);
526 return status;
527}
528
529static u32 clk_prog_construct_super(struct gk20a *g,
530 struct boardobj **ppboardobj,
531 u16 size, void *pargs)
532{
533 struct clk_prog *pclkprog;
534 u32 status = 0;
535
536 status = boardobj_construct_super(g, ppboardobj,
537 size, pargs);
538 if (status)
539 return -EINVAL;
540
541 pclkprog = (struct clk_prog *)*ppboardobj;
542
543 pclkprog->super.pmudatainit =
544 _clk_prog_pmudatainit_super;
545 return status;
546}
547
548
549static u32 clk_prog_construct_1x(struct gk20a *g,
550 struct boardobj **ppboardobj,
551 u16 size, void *pargs)
552{
553 struct boardobj *ptmpobj = (struct boardobj *)pargs;
554 struct clk_prog_1x *pclkprog;
555 struct clk_prog_1x *ptmpprog =
556 (struct clk_prog_1x *)pargs;
557 u32 status = 0;
558
559 gk20a_dbg_info(" ");
560 ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_PROG_TYPE_1X);
561 status = clk_prog_construct_super(g, ppboardobj, size, pargs);
562 if (status)
563 return -EINVAL;
564
565 pclkprog = (struct clk_prog_1x *)*ppboardobj;
566
567 pclkprog->super.super.pmudatainit =
568 _clk_prog_pmudatainit_1x;
569
570 pclkprog->source = ptmpprog->source;
571 pclkprog->freq_max_mhz = ptmpprog->freq_max_mhz;
572 pclkprog->source_data = ptmpprog->source_data;
573
574 return status;
575}
576
577static u32 clk_prog_construct_1x_master(struct gk20a *g,
578 struct boardobj **ppboardobj,
579 u16 size, void *pargs)
580{
581 struct boardobj *ptmpobj = (struct boardobj *)pargs;
582 struct clk_prog_1x_master *pclkprog;
583 struct clk_prog_1x_master *ptmpprog =
584 (struct clk_prog_1x_master *)pargs;
585 u32 status = 0;
586 u32 vfsize = sizeof(struct ctrl_clk_clk_prog_1x_master_vf_entry) *
587 g->clk_pmu.clk_progobjs.vf_entry_count;
588 u8 railidx;
589
590 gk20a_dbg_info(" type - %x", BOARDOBJ_GET_TYPE(pargs));
591
592 ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_PROG_TYPE_1X_MASTER);
593 status = clk_prog_construct_1x(g, ppboardobj, size, pargs);
594 if (status)
595 return -EINVAL;
596
597 pclkprog = (struct clk_prog_1x_master *)*ppboardobj;
598
599 pclkprog->super.super.super.pmudatainit =
600 _clk_prog_pmudatainit_1x_master;
601
602 pclkprog->vfflatten =
603 vfflatten_prog_1x_master;
604
605 pclkprog->p_vf_entries = (struct ctrl_clk_clk_prog_1x_master_vf_entry *)
606 kzalloc(vfsize, GFP_KERNEL);
607
608 memcpy(pclkprog->p_vf_entries, ptmpprog->p_vf_entries, vfsize);
609
610 pclkprog->b_o_c_o_v_enabled = ptmpprog->b_o_c_o_v_enabled;
611
612 for (railidx = 0;
613 railidx < g->clk_pmu.clk_progobjs.vf_entry_count;
614 railidx++) {
615 pclkprog->p_vf_entries[railidx].vf_point_idx_first =
616 CTRL_CLK_CLK_VF_POINT_IDX_INVALID;
617 pclkprog->p_vf_entries[railidx].vf_point_idx_last =
618 CTRL_CLK_CLK_VF_POINT_IDX_INVALID;
619 }
620
621 return status;
622}
623
624static u32 clk_prog_construct_1x_master_ratio(struct gk20a *g,
625 struct boardobj **ppboardobj,
626 u16 size, void *pargs)
627{
628 struct boardobj *ptmpobj = (struct boardobj *)pargs;
629 struct clk_prog_1x_master_ratio *pclkprog;
630 struct clk_prog_1x_master_ratio *ptmpprog =
631 (struct clk_prog_1x_master_ratio *)pargs;
632 u32 status = 0;
633 u32 slavesize = sizeof(struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry) *
634 g->clk_pmu.clk_progobjs.slave_entry_count;
635
636 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_RATIO)
637 return -EINVAL;
638
639 ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_RATIO);
640 status = clk_prog_construct_1x_master(g, ppboardobj, size, pargs);
641 if (status)
642 return -EINVAL;
643
644 pclkprog = (struct clk_prog_1x_master_ratio *)*ppboardobj;
645
646 pclkprog->super.super.super.super.pmudatainit =
647 _clk_prog_pmudatainit_1x_master_ratio;
648
649 pclkprog->p_slave_entries =
650 (struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry *)
651 kzalloc(slavesize, GFP_KERNEL);
652 if (!pclkprog->p_slave_entries)
653 return -ENOMEM;
654
655 memset(pclkprog->p_slave_entries, CTRL_CLK_CLK_DOMAIN_INDEX_INVALID,
656 slavesize);
657
658 memcpy(pclkprog->p_slave_entries, ptmpprog->p_slave_entries, slavesize);
659
660 return status;
661}
662
663static u32 clk_prog_construct_1x_master_table(struct gk20a *g,
664 struct boardobj **ppboardobj,
665 u16 size, void *pargs)
666{
667 struct boardobj *ptmpobj = (struct boardobj *)pargs;
668 struct clk_prog_1x_master_table *pclkprog;
669 struct clk_prog_1x_master_table *ptmpprog =
670 (struct clk_prog_1x_master_table *)pargs;
671 u32 status = 0;
672 u32 slavesize = sizeof(struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry) *
673 g->clk_pmu.clk_progobjs.slave_entry_count;
674
675 gk20a_dbg_info("type - %x", BOARDOBJ_GET_TYPE(pargs));
676
677 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_TABLE)
678 return -EINVAL;
679
680 ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_TABLE);
681 status = clk_prog_construct_1x_master(g, ppboardobj, size, pargs);
682 if (status)
683 return -EINVAL;
684
685 pclkprog = (struct clk_prog_1x_master_table *)*ppboardobj;
686
687 pclkprog->super.super.super.super.pmudatainit =
688 _clk_prog_pmudatainit_1x_master_table;
689
690 pclkprog->p_slave_entries =
691 (struct ctrl_clk_clk_prog_1x_master_table_slave_entry *)
692 kzalloc(slavesize, GFP_KERNEL);
693 if (!pclkprog->p_slave_entries)
694 return -ENOMEM;
695
696 memset(pclkprog->p_slave_entries, CTRL_CLK_CLK_DOMAIN_INDEX_INVALID,
697 slavesize);
698
699 memcpy(pclkprog->p_slave_entries, ptmpprog->p_slave_entries, slavesize);
700
701 return status;
702}
703
704static struct clk_prog *construct_clk_prog(struct gk20a *g, void *pargs)
705{
706 struct boardobj *board_obj_ptr = NULL;
707 u32 status;
708
709 gk20a_dbg_info(" type - %x", BOARDOBJ_GET_TYPE(pargs));
710 switch (BOARDOBJ_GET_TYPE(pargs)) {
711 case CTRL_CLK_CLK_PROG_TYPE_1X:
712 status = clk_prog_construct_1x(g, &board_obj_ptr,
713 sizeof(struct clk_prog_1x), pargs);
714 break;
715
716 case CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_TABLE:
717 status = clk_prog_construct_1x_master_table(g, &board_obj_ptr,
718 sizeof(struct clk_prog_1x_master_table), pargs);
719 break;
720
721 case CTRL_CLK_CLK_PROG_TYPE_1X_MASTER_RATIO:
722 status = clk_prog_construct_1x_master_ratio(g, &board_obj_ptr,
723 sizeof(struct clk_prog_1x_master_ratio), pargs);
724 break;
725
726 default:
727 return NULL;
728 }
729
730 if (status)
731 return NULL;
732
733 gk20a_dbg_info(" Done");
734
735 return (struct clk_prog *)board_obj_ptr;
736}
737
738static u32 vfflatten_prog_1x_master(struct gk20a *g,
739 struct clk_pmupstate *pclk,
740 struct clk_prog_1x_master *p1xmaster,
741 u8 clk_domain_idx, u16 *pfreqmaxlastmhz)
742{
743 struct ctrl_clk_clk_prog_1x_master_vf_entry *p_vf_rail;
744 union {
745 struct boardobj board_obj;
746 struct clk_vf_point vf_point;
747 struct clk_vf_point_freq freq;
748 struct clk_vf_point_volt volt;
749 } vf_point_data;
750 u32 status = 0;
751 u8 step_count;
752 u8 freq_step_size_mhz = 0;
753 u8 vf_point_idx;
754 u8 vf_rail_idx;
755
756 gk20a_dbg_info("");
757 memset(&vf_point_data, 0x0, sizeof(vf_point_data));
758
759 vf_point_idx = BOARDOBJGRP_NEXT_EMPTY_IDX(
760 &pclk->clk_vf_pointobjs.super.super);
761
762 for (vf_rail_idx = 0;
763 vf_rail_idx < pclk->clk_progobjs.vf_entry_count;
764 vf_rail_idx++) {
765 u32 voltage_min_uv;
766 u32 voltage_step_size_uv;
767 u8 i;
768
769 p_vf_rail = &p1xmaster->p_vf_entries[vf_rail_idx];
770 if (p_vf_rail->vfe_idx == CTRL_BOARDOBJ_IDX_INVALID)
771 continue;
772
773 p_vf_rail->vf_point_idx_first = vf_point_idx;
774
775 vf_point_data.vf_point.vfe_equ_idx = p_vf_rail->vfe_idx;
776 vf_point_data.vf_point.volt_rail_idx = vf_rail_idx;
777
778 step_count = 0;
779
780 switch (p1xmaster->super.source) {
781 case CTRL_CLK_PROG_1X_SOURCE_PLL:
782 freq_step_size_mhz =
783 p1xmaster->super.source_data.pll.freq_step_size_mhz;
784 step_count = (freq_step_size_mhz == 0) ? 0 :
785 (p1xmaster->super.freq_max_mhz - *pfreqmaxlastmhz - 1) /
786 freq_step_size_mhz;
787 /* Intentional fall-through.*/
788
789 case CTRL_CLK_PROG_1X_SOURCE_ONE_SOURCE:
790 vf_point_data.board_obj.type =
791 CTRL_CLK_CLK_VF_POINT_TYPE_FREQ;
792 do {
793 clkvfpointfreqmhzset(g, &vf_point_data.vf_point,
794 p1xmaster->super.freq_max_mhz -
795 step_count * freq_step_size_mhz);
796
797 status = _clk_prog_1x_master_rail_construct_vf_point(g, pclk,
798 p1xmaster, p_vf_rail,
799 &vf_point_data.vf_point, &vf_point_idx);
800 if (status)
801 goto done;
802 } while (step_count-- > 0);
803 break;
804
805 case CTRL_CLK_PROG_1X_SOURCE_FLL:
806 voltage_min_uv = CLK_FLL_LUT_MIN_VOLTAGE_UV(pclk);
807 voltage_step_size_uv = CLK_FLL_LUT_STEP_SIZE_UV(pclk);
808 step_count = CLK_FLL_LUT_VF_NUM_ENTRIES(pclk);
809
810 /* FLL sources use a voltage-based VF_POINT.*/
811 vf_point_data.board_obj.type =
812 CTRL_CLK_CLK_VF_POINT_TYPE_VOLT;
813 vf_point_data.volt.clk_domain_idx = clk_domain_idx;
814 for (i = 0; i < step_count; i++) {
815 vf_point_data.volt.source_voltage_uv =
816 voltage_min_uv + i * voltage_step_size_uv;
817 vf_point_data.volt.vf_gain_vfe_equ_idx = p_vf_rail->gain_vfe_idx;
818
819 status = _clk_prog_1x_master_rail_construct_vf_point(g, pclk,
820 p1xmaster, p_vf_rail,
821 &vf_point_data.vf_point, &vf_point_idx);
822 if (status)
823 goto done;
824 }
825 break;
826 }
827 }
828
829 *pfreqmaxlastmhz = p1xmaster->super.freq_max_mhz;
830
831done:
832 gk20a_dbg_info("done status %x", status);
833 return status;
834}
diff --git a/drivers/gpu/nvgpu/clk/clk_prog.h b/drivers/gpu/nvgpu/clk/clk_prog.h
new file mode 100644
index 00000000..2dd8f6c8
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk_prog.h
@@ -0,0 +1,71 @@
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#ifndef _CLKPROG_H_
15#define _CLKPROG_H_
16#include "ctrl/ctrlclk.h"
17#include "ctrl/ctrlboardobj.h"
18#include "pmuif/gpmuifclk.h"
19#include "boardobj/boardobjgrp_e32.h"
20#include "boardobj/boardobjgrpmask.h"
21
22u32 clk_prog_sw_setup(struct gk20a *g);
23u32 clk_prog_pmu_setup(struct gk20a *g);
24struct clk_prog_1x_master;
25
26typedef u32 vf_flatten(struct gk20a *g, struct clk_pmupstate *pclk,
27 struct clk_prog_1x_master *p1xmaster,
28 u8 clk_domain_idx, u16 *pfreqmaxlastmhz);
29
30struct clk_progs {
31 struct boardobjgrp_e255 super;
32 u8 slave_entry_count;
33 u8 vf_entry_count;
34
35};
36
37struct clk_prog {
38 struct boardobj super;
39};
40
41struct clk_prog_1x {
42 struct clk_prog super;
43 u8 source;
44 u16 freq_max_mhz;
45 union ctrl_clk_clk_prog_1x_source_data source_data;
46};
47
48struct clk_prog_1x_master {
49 struct clk_prog_1x super;
50 bool b_o_c_o_v_enabled;
51 struct ctrl_clk_clk_prog_1x_master_vf_entry *p_vf_entries;
52
53 struct ctrl_clk_clk_delta deltas;
54 vf_flatten *vfflatten;
55};
56
57struct clk_prog_1x_master_ratio {
58 struct clk_prog_1x_master super;
59 struct ctrl_clk_clk_prog_1x_master_ratio_slave_entry *p_slave_entries;
60};
61
62struct clk_prog_1x_master_table {
63 struct clk_prog_1x_master super;
64 struct ctrl_clk_clk_prog_1x_master_table_slave_entry *p_slave_entries;
65};
66
67#define CLK_CLK_PROG_GET(pclk, idx) \
68 ((struct clk_prog *)BOARDOBJGRP_OBJ_GET_BY_IDX( \
69 &pclk->clk_progobjs.super.super, (u8)(idx)))
70
71#endif
diff --git a/drivers/gpu/nvgpu/clk/clk_vf_point.c b/drivers/gpu/nvgpu/clk/clk_vf_point.c
new file mode 100644
index 00000000..275bef96
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk_vf_point.c
@@ -0,0 +1,347 @@
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_vf_point.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 _clk_vf_point_pmudatainit_super(struct gk20a *g, struct boardobj
28 *board_obj_ptr, struct nv_pmu_boardobj *ppmudata);
29
30static u32 _clk_vf_points_pmudatainit(struct gk20a *g,
31 struct boardobjgrp *pboardobjgrp,
32 struct nv_pmu_boardobjgrp_super *pboardobjgrppmu)
33{
34 u32 status = 0;
35
36 status = boardobjgrp_pmudatainit_e32(g, pboardobjgrp, pboardobjgrppmu);
37 if (status) {
38 gk20a_err(dev_from_gk20a(g),
39 "error updating pmu boardobjgrp for clk vfpoint 0x%x",
40 status);
41 goto done;
42 }
43
44done:
45 return status;
46}
47
48static u32 _clk_vf_points_pmudata_instget(struct gk20a *g,
49 struct nv_pmu_boardobjgrp *pmuboardobjgrp,
50 struct nv_pmu_boardobj **ppboardobjpmudata,
51 u8 idx)
52{
53 struct nv_pmu_clk_clk_vf_point_boardobj_grp_set *pgrp_set =
54 (struct nv_pmu_clk_clk_vf_point_boardobj_grp_set *)
55 pmuboardobjgrp;
56
57 gk20a_dbg_info("");
58
59 /*check whether pmuboardobjgrp has a valid boardobj in index*/
60 if (idx >= CTRL_BOARDOBJGRP_E255_MAX_OBJECTS)
61 return -EINVAL;
62
63 *ppboardobjpmudata = (struct nv_pmu_boardobj *)
64 &pgrp_set->objects[idx].data.board_obj;
65 gk20a_dbg_info(" Done");
66 return 0;
67}
68
69static u32 _clk_vf_points_pmustatus_instget(struct gk20a *g,
70 void *pboardobjgrppmu,
71 struct nv_pmu_boardobj_query **ppboardobjpmustatus,
72 u8 idx)
73{
74 struct nv_pmu_clk_clk_vf_point_boardobj_grp_get_status *pgrp_get_status =
75 (struct nv_pmu_clk_clk_vf_point_boardobj_grp_get_status *)
76 pboardobjgrppmu;
77
78 /*check whether pmuboardobjgrp has a valid boardobj in index*/
79 if (idx >= CTRL_BOARDOBJGRP_E255_MAX_OBJECTS)
80 return -EINVAL;
81
82 *ppboardobjpmustatus = (struct nv_pmu_boardobj_query *)
83 &pgrp_get_status->objects[idx].data.board_obj;
84 return 0;
85}
86
87u32 clk_vf_point_sw_setup(struct gk20a *g)
88{
89 u32 status;
90 struct boardobjgrp *pboardobjgrp = NULL;
91 struct clk_vf_points *pclkvfpointobjs;
92
93 gk20a_dbg_info("");
94
95 status = boardobjgrpconstruct_e255(&g->clk_pmu.clk_vf_pointobjs.super);
96 if (status) {
97 gk20a_err(dev_from_gk20a(g),
98 "error creating boardobjgrp for clk vfpoint, status - 0x%x",
99 status);
100 goto done;
101 }
102
103 pboardobjgrp = &g->clk_pmu.clk_vf_pointobjs.super.super;
104 pclkvfpointobjs = &(g->clk_pmu.clk_vf_pointobjs);
105
106 BOARDOBJGRP_PMU_CONSTRUCT(pboardobjgrp, CLK, CLK_VF_POINT);
107
108 status = BOARDOBJGRP_PMU_CMD_GRP_SET_CONSTRUCT(g, pboardobjgrp,
109 clk, CLK, clk_vf_point, CLK_VF_POINT);
110 if (status) {
111 gk20a_err(dev_from_gk20a(g),
112 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
113 status);
114 goto done;
115 }
116
117 status = BOARDOBJGRP_PMU_CMD_GRP_GET_STATUS_CONSTRUCT(g,
118 &g->clk_pmu.clk_vf_pointobjs.super.super,
119 clk, CLK, clk_vf_point, CLK_VF_POINT);
120 if (status) {
121 gk20a_err(dev_from_gk20a(g),
122 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
123 status);
124 goto done;
125 }
126
127 pboardobjgrp->pmudatainit = _clk_vf_points_pmudatainit;
128 pboardobjgrp->pmudatainstget = _clk_vf_points_pmudata_instget;
129 pboardobjgrp->pmustatusinstget = _clk_vf_points_pmustatus_instget;
130
131done:
132 gk20a_dbg_info(" done status %x", status);
133 return status;
134}
135
136u32 clk_vf_point_pmu_setup(struct gk20a *g)
137{
138 u32 status;
139 struct boardobjgrp *pboardobjgrp = NULL;
140
141 gk20a_dbg_info("");
142
143 pboardobjgrp = &g->clk_pmu.clk_vf_pointobjs.super.super;
144
145 if (!pboardobjgrp->bconstructed)
146 return -EINVAL;
147
148 status = pboardobjgrp->pmuinithandle(g, pboardobjgrp);
149
150 gk20a_dbg_info("Done");
151 return status;
152}
153
154static u32 clk_vf_point_construct_super(struct gk20a *g,
155 struct boardobj **ppboardobj,
156 u16 size, void *pargs)
157{
158 struct clk_vf_point *pclkvfpoint;
159 struct clk_vf_point *ptmpvfpoint =
160 (struct clk_vf_point *)pargs;
161 u32 status = 0;
162
163 status = boardobj_construct_super(g, ppboardobj,
164 size, pargs);
165 if (status)
166 return -EINVAL;
167
168 pclkvfpoint = (struct clk_vf_point *)*ppboardobj;
169
170 pclkvfpoint->super.pmudatainit =
171 _clk_vf_point_pmudatainit_super;
172
173 pclkvfpoint->vfe_equ_idx = ptmpvfpoint->vfe_equ_idx;
174 pclkvfpoint->volt_rail_idx = ptmpvfpoint->volt_rail_idx;
175
176 return status;
177}
178
179static u32 _clk_vf_point_pmudatainit_volt(struct gk20a *g,
180 struct boardobj *board_obj_ptr,
181 struct nv_pmu_boardobj *ppmudata)
182{
183 u32 status = 0;
184 struct clk_vf_point_volt *pclk_vf_point_volt;
185 struct nv_pmu_clk_clk_vf_point_volt_boardobj_set *pset;
186
187 gk20a_dbg_info("");
188
189 status = _clk_vf_point_pmudatainit_super(g, board_obj_ptr, ppmudata);
190 if (status != 0)
191 return status;
192
193 pclk_vf_point_volt =
194 (struct clk_vf_point_volt *)board_obj_ptr;
195
196 pset = (struct nv_pmu_clk_clk_vf_point_volt_boardobj_set *)
197 ppmudata;
198
199 pset->source_voltage_uv = pclk_vf_point_volt->source_voltage_uv;
200 pset->vf_gain_vfe_equ_idx = pclk_vf_point_volt->vf_gain_vfe_equ_idx;
201 pset->clk_domain_idx = pclk_vf_point_volt->clk_domain_idx;
202 pset->freq_delta_khz = pclk_vf_point_volt->freq_delta_khz;
203
204 return status;
205}
206
207static u32 _clk_vf_point_pmudatainit_freq(struct gk20a *g,
208 struct boardobj *board_obj_ptr,
209 struct nv_pmu_boardobj *ppmudata)
210{
211 u32 status = 0;
212 struct clk_vf_point_freq *pclk_vf_point_freq;
213 struct nv_pmu_clk_clk_vf_point_freq_boardobj_set *pset;
214
215 gk20a_dbg_info("");
216
217 status = _clk_vf_point_pmudatainit_super(g, board_obj_ptr, ppmudata);
218 if (status != 0)
219 return status;
220
221 pclk_vf_point_freq =
222 (struct clk_vf_point_freq *)board_obj_ptr;
223
224 pset = (struct nv_pmu_clk_clk_vf_point_freq_boardobj_set *)
225 ppmudata;
226
227 pset->freq_mhz =
228 clkvfpointfreqmhzget(g, &pclk_vf_point_freq->super);
229
230 pset->volt_delta_uv = pclk_vf_point_freq->volt_delta_uv;
231
232 return status;
233}
234
235static u32 clk_vf_point_construct_volt(struct gk20a *g,
236 struct boardobj **ppboardobj,
237 u16 size, void *pargs)
238{
239 struct boardobj *ptmpobj = (struct boardobj *)pargs;
240 struct clk_vf_point_volt *pclkvfpoint;
241 struct clk_vf_point_volt *ptmpvfpoint =
242 (struct clk_vf_point_volt *)pargs;
243 u32 status = 0;
244
245 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_CLK_CLK_VF_POINT_TYPE_VOLT)
246 return -EINVAL;
247
248 ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_VF_POINT_TYPE_VOLT);
249 status = clk_vf_point_construct_super(g, ppboardobj, size, pargs);
250 if (status)
251 return -EINVAL;
252
253 pclkvfpoint = (struct clk_vf_point_volt *)*ppboardobj;
254
255 pclkvfpoint->super.super.pmudatainit =
256 _clk_vf_point_pmudatainit_volt;
257
258 pclkvfpoint->source_voltage_uv = ptmpvfpoint->source_voltage_uv;
259 pclkvfpoint->vf_gain_vfe_equ_idx = ptmpvfpoint->vf_gain_vfe_equ_idx;
260 pclkvfpoint->clk_domain_idx = ptmpvfpoint->clk_domain_idx;
261
262 return status;
263}
264
265static u32 clk_vf_point_construct_freq(struct gk20a *g,
266 struct boardobj **ppboardobj,
267 u16 size, void *pargs)
268{
269 struct boardobj *ptmpobj = (struct boardobj *)pargs;
270 struct clk_vf_point_freq *pclkvfpoint;
271 struct clk_vf_point_freq *ptmpvfpoint =
272 (struct clk_vf_point_freq *)pargs;
273 u32 status = 0;
274
275 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_CLK_CLK_VF_POINT_TYPE_FREQ)
276 return -EINVAL;
277
278 ptmpobj->type_mask |= BIT(CTRL_CLK_CLK_VF_POINT_TYPE_FREQ);
279 status = clk_vf_point_construct_super(g, ppboardobj, size, pargs);
280 if (status)
281 return -EINVAL;
282
283 pclkvfpoint = (struct clk_vf_point_freq *)*ppboardobj;
284
285 pclkvfpoint->super.super.pmudatainit =
286 _clk_vf_point_pmudatainit_freq;
287
288 clkvfpointfreqmhzset(g, &pclkvfpoint->super,
289 clkvfpointfreqmhzget(g, &ptmpvfpoint->super));
290
291 return status;
292}
293
294struct clk_vf_point *construct_clk_vf_point(struct gk20a *g, void *pargs)
295{
296 struct boardobj *board_obj_ptr = NULL;
297 u32 status;
298
299 gk20a_dbg_info("");
300 switch (BOARDOBJ_GET_TYPE(pargs)) {
301 case CTRL_CLK_CLK_VF_POINT_TYPE_FREQ:
302 status = clk_vf_point_construct_freq(g, &board_obj_ptr,
303 sizeof(struct clk_vf_point_freq), pargs);
304 break;
305
306 case CTRL_CLK_CLK_VF_POINT_TYPE_VOLT:
307 status = clk_vf_point_construct_volt(g, &board_obj_ptr,
308 sizeof(struct clk_vf_point_volt), pargs);
309 break;
310
311 default:
312 return NULL;
313 }
314
315 if (status)
316 return NULL;
317
318 gk20a_dbg_info(" Done");
319
320 return (struct clk_vf_point *)board_obj_ptr;
321}
322
323static u32 _clk_vf_point_pmudatainit_super(struct gk20a *g,
324 struct boardobj *board_obj_ptr,
325 struct nv_pmu_boardobj *ppmudata)
326{
327 u32 status = 0;
328 struct clk_vf_point *pclk_vf_point;
329 struct nv_pmu_clk_clk_vf_point_boardobj_set *pset;
330
331 gk20a_dbg_info("");
332
333 status = boardobj_pmudatainit_super(g, board_obj_ptr, ppmudata);
334 if (status != 0)
335 return status;
336
337 pclk_vf_point =
338 (struct clk_vf_point *)board_obj_ptr;
339
340 pset = (struct nv_pmu_clk_clk_vf_point_boardobj_set *)
341 ppmudata;
342
343
344 pset->vfe_equ_idx = pclk_vf_point->vfe_equ_idx;
345 pset->volt_rail_idx = pclk_vf_point->volt_rail_idx;
346 return status;
347}
diff --git a/drivers/gpu/nvgpu/clk/clk_vf_point.h b/drivers/gpu/nvgpu/clk/clk_vf_point.h
new file mode 100644
index 00000000..708f80f1
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk_vf_point.h
@@ -0,0 +1,74 @@
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#ifndef _CLKVFPOINT_H_
15#define _CLKVFPOINT_H_
16#include "ctrl/ctrlclk.h"
17#include "ctrl/ctrlboardobj.h"
18#include "pmuif/gpmuifclk.h"
19#include "boardobj/boardobjgrp_e32.h"
20#include "boardobj/boardobjgrpmask.h"
21
22u32 clk_vf_point_sw_setup(struct gk20a *g);
23u32 clk_vf_point_pmu_setup(struct gk20a *g);
24
25struct clk_vf_points {
26 struct boardobjgrp_e255 super;
27};
28
29struct clk_vf_point {
30 struct boardobj super;
31 u8 vfe_equ_idx;
32 u8 volt_rail_idx;
33 struct ctrl_clk_vf_pair pair;
34};
35
36struct clk_vf_point_volt {
37 struct clk_vf_point super;
38 u32 source_voltage_uv;
39 u8 vf_gain_vfe_equ_idx;
40 u8 clk_domain_idx;
41 u16 vf_gain_value;
42 int freq_delta_khz;
43
44};
45
46struct clk_vf_point_freq {
47 struct clk_vf_point super;
48 int volt_delta_uv;
49};
50
51#define CLK_CLK_VF_POINT_GET(pclk, idx) \
52 ((struct clk_vf_point)BOARDOBJGRP_OBJ_GET_BY_IDX( \
53 &pclk->vfpoints.super.super, (u8)(idx)))
54
55#define clkvfpointpairget(pvfpoint) \
56 (&((pvfpoint)->pair))
57
58#define clkvfpointfreqmhzget(pgpu, pvfpoint) \
59 CTRL_CLK_VF_PAIR_FREQ_MHZ_GET(clkvfpointpairget(pvfpoint))
60
61#define clkvfpointfreqdeltamhzGet(pgpu, pvfPoint) \
62 ((BOARDOBJ_GET_TYPE(pvfpoint) == CTRL_CLK_CLK_VF_POINT_TYPE_VOLT) ? \
63 (((struct clk_vf_point_volt *)(pvfpoint))->freq_delta_khz / 1000) : 0)
64
65#define clkvfpointfreqmhzset(pgpu, pvfpoint, _freqmhz) \
66 CTRL_CLK_VF_PAIR_FREQ_MHZ_SET(clkvfpointpairget(pvfpoint), _freqmhz)
67
68#define clkvfpointvoltageuvset(pgpu, pvfpoint, _voltageuv) \
69 CTRL_CLK_VF_PAIR_VOLTAGE_UV_SET(clkvfpointpairget(pvfpoint), \
70 _voltageuv)
71
72struct clk_vf_point *construct_clk_vf_point(struct gk20a *g, void *pargs);
73
74#endif
diff --git a/drivers/gpu/nvgpu/clk/clk_vin.c b/drivers/gpu/nvgpu/clk/clk_vin.c
new file mode 100644
index 00000000..e8e4b753
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk_vin.c
@@ -0,0 +1,466 @@
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_vin.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/ctrlvolt.h"
24#include "gk20a/pmu_gk20a.h"
25#include "gp106/hw_fuse_gp106.h"
26
27static u32 devinit_get_vin_device_table(struct gk20a *g,
28 struct avfsvinobjs *pvinobjs);
29
30static struct vin_device *construct_vin_device(struct gk20a *g, void *pargs);
31
32static u32 vin_device_init_pmudata_super(struct gk20a *g,
33 struct boardobj *board_obj_ptr,
34 struct nv_pmu_boardobj *ppmudata);
35
36static u32 read_vin_cal_fuse_rev(struct gk20a *g)
37{
38 return fuse_vin_cal_fuse_rev_v(
39 gk20a_readl(g, fuse_vin_cal_fuse_rev_r()));
40}
41
42static u32 read_vin_cal_slope_intercept_fuse(struct gk20a *g,
43 u32 vin_id, u32 *slope,
44 u32 *intercept)
45{
46 u32 data = 0;
47 u32 interceptdata = 0;
48 u32 slopedata = 0;
49 u32 gpc0data;
50 u32 gpc0slopedata;
51 u32 gpc0interceptdata;
52
53 /* read gpc0 irrespective of vin id */
54 gpc0data = gk20a_readl(g, fuse_vin_cal_gpc0_r());
55 if (gpc0data == 0xFFFFFFFF)
56 return -EINVAL;
57
58 switch (vin_id) {
59 case CTRL_CLK_VIN_ID_GPC0:
60 break;
61
62 case CTRL_CLK_VIN_ID_GPC1:
63 data = gk20a_readl(g, fuse_vin_cal_gpc1_delta_r());
64 break;
65
66 case CTRL_CLK_VIN_ID_GPC2:
67 data = gk20a_readl(g, fuse_vin_cal_gpc2_delta_r());
68 break;
69
70 case CTRL_CLK_VIN_ID_GPC3:
71 data = gk20a_readl(g, fuse_vin_cal_gpc3_delta_r());
72 break;
73
74 case CTRL_CLK_VIN_ID_GPC4:
75 data = gk20a_readl(g, fuse_vin_cal_gpc4_delta_r());
76 break;
77
78 case CTRL_CLK_VIN_ID_GPC5:
79 data = gk20a_readl(g, fuse_vin_cal_gpc5_delta_r());
80 break;
81
82 case CTRL_CLK_VIN_ID_SYS:
83 case CTRL_CLK_VIN_ID_XBAR:
84 case CTRL_CLK_VIN_ID_LTC:
85 data = gk20a_readl(g, fuse_vin_cal_shared_delta_r());
86 break;
87
88 case CTRL_CLK_VIN_ID_SRAM:
89 data = gk20a_readl(g, fuse_vin_cal_sram_delta_r());
90 break;
91
92 default:
93 return -EINVAL;
94 }
95 if (data == 0xFFFFFFFF)
96 return -EINVAL;
97
98 gpc0interceptdata = fuse_vin_cal_gpc0_icpt_data_v(gpc0data) * 1000;
99 gpc0interceptdata = gpc0interceptdata >>
100 fuse_vin_cal_gpc0_icpt_frac_size_v();
101
102 switch (vin_id) {
103 case CTRL_CLK_VIN_ID_GPC0:
104 break;
105
106 case CTRL_CLK_VIN_ID_GPC1:
107 case CTRL_CLK_VIN_ID_GPC2:
108 case CTRL_CLK_VIN_ID_GPC3:
109 case CTRL_CLK_VIN_ID_GPC4:
110 case CTRL_CLK_VIN_ID_GPC5:
111 case CTRL_CLK_VIN_ID_SYS:
112 case CTRL_CLK_VIN_ID_XBAR:
113 case CTRL_CLK_VIN_ID_LTC:
114 interceptdata =
115 (fuse_vin_cal_gpc1_icpt_data_v(data)) * 1000;
116 interceptdata = interceptdata >>
117 fuse_vin_cal_gpc1_icpt_frac_size_v();
118 break;
119
120 case CTRL_CLK_VIN_ID_SRAM:
121 interceptdata =
122 (fuse_vin_cal_sram_icpt_data_v(data)) * 1000;
123 interceptdata = interceptdata >>
124 fuse_vin_cal_sram_icpt_frac_size_v();
125 break;
126
127 default:
128 return -EINVAL;
129 }
130
131 if (data & fuse_vin_cal_gpc1_icpt_sign_f())
132 *intercept = gpc0interceptdata - interceptdata;
133 else
134 *intercept = gpc0interceptdata + interceptdata;
135
136 /* slope */
137 gpc0slopedata = (fuse_vin_cal_gpc0_slope_data_v(gpc0data)) * 1000;
138 gpc0slopedata = gpc0slopedata >>
139 fuse_vin_cal_gpc0_slope_frac_size_v();
140
141 switch (vin_id) {
142 case CTRL_CLK_VIN_ID_GPC0:
143 break;
144
145 case CTRL_CLK_VIN_ID_GPC1:
146 case CTRL_CLK_VIN_ID_GPC2:
147 case CTRL_CLK_VIN_ID_GPC3:
148 case CTRL_CLK_VIN_ID_GPC4:
149 case CTRL_CLK_VIN_ID_GPC5:
150 case CTRL_CLK_VIN_ID_SYS:
151 case CTRL_CLK_VIN_ID_XBAR:
152 case CTRL_CLK_VIN_ID_LTC:
153 case CTRL_CLK_VIN_ID_SRAM:
154 slopedata =
155 (fuse_vin_cal_gpc1_slope_data_v(data)) * 1000;
156 slopedata = slopedata >>
157 fuse_vin_cal_gpc1_slope_frac_size_v();
158 break;
159
160 default:
161 return -EINVAL;
162 }
163
164 if (data & fuse_vin_cal_gpc1_slope_sign_f())
165 *slope = gpc0slopedata - slopedata;
166 else
167 *slope = gpc0slopedata + slopedata;
168 return 0;
169}
170
171static u32 _clk_vin_devgrp_pmudatainit_super(struct gk20a *g,
172 struct boardobjgrp *pboardobjgrp,
173 struct nv_pmu_boardobjgrp_super *pboardobjgrppmu)
174{
175 struct nv_pmu_clk_clk_vin_device_boardobjgrp_set_header *pset =
176 (struct nv_pmu_clk_clk_vin_device_boardobjgrp_set_header *)
177 pboardobjgrppmu;
178 struct avfsvinobjs *pvin_obbj = (struct avfsvinobjs *)pboardobjgrp;
179 u32 status = 0;
180
181 gk20a_dbg_info("");
182
183 status = boardobjgrp_pmudatainit_e32(g, pboardobjgrp, pboardobjgrppmu);
184
185 pset->b_vin_is_disable_allowed = pvin_obbj->vin_is_disable_allowed;
186
187 gk20a_dbg_info(" Done");
188 return status;
189}
190
191static u32 _clk_vin_devgrp_pmudata_instget(struct gk20a *g,
192 struct nv_pmu_boardobjgrp *pmuboardobjgrp,
193 struct nv_pmu_boardobj **ppboardobjpmudata,
194 u8 idx)
195{
196 struct nv_pmu_clk_clk_vin_device_boardobj_grp_set *pgrp_set =
197 (struct nv_pmu_clk_clk_vin_device_boardobj_grp_set *)
198 pmuboardobjgrp;
199
200 gk20a_dbg_info("");
201
202 /*check whether pmuboardobjgrp has a valid boardobj in index*/
203 if (((u32)BIT(idx) &
204 pgrp_set->hdr.data.super.obj_mask.super.data[0]) == 0)
205 return -EINVAL;
206
207 *ppboardobjpmudata = (struct nv_pmu_boardobj *)
208 &pgrp_set->objects[idx].data.board_obj;
209 gk20a_dbg_info(" Done");
210 return 0;
211}
212
213static u32 _clk_vin_devgrp_pmustatus_instget(struct gk20a *g,
214 void *pboardobjgrppmu,
215 struct nv_pmu_boardobj_query **ppboardobjpmustatus,
216 u8 idx)
217{
218 struct nv_pmu_clk_clk_vin_device_boardobj_grp_get_status *pgrp_get_status =
219 (struct nv_pmu_clk_clk_vin_device_boardobj_grp_get_status *)
220 pboardobjgrppmu;
221
222 /*check whether pmuboardobjgrp has a valid boardobj in index*/
223 if (((u32)BIT(idx) &
224 pgrp_get_status->hdr.data.super.obj_mask.super.data[0]) == 0)
225 return -EINVAL;
226
227 *ppboardobjpmustatus = (struct nv_pmu_boardobj_query *)
228 &pgrp_get_status->objects[idx].data.board_obj;
229 return 0;
230}
231
232u32 clk_vin_sw_setup(struct gk20a *g)
233{
234 u32 status;
235 struct boardobjgrp *pboardobjgrp = NULL;
236 u32 slope;
237 u32 intercept;
238 struct vin_device *pvindev;
239 struct avfsvinobjs *pvinobjs;
240 u8 i;
241
242 gk20a_dbg_info("");
243
244 status = boardobjgrpconstruct_e32(&g->clk_pmu.avfs_vinobjs.super);
245 if (status) {
246 gk20a_err(dev_from_gk20a(g),
247 "error creating boardobjgrp for clk vin, statu - 0x%x",
248 status);
249 goto done;
250 }
251
252 pboardobjgrp = &g->clk_pmu.avfs_vinobjs.super.super;
253 pvinobjs = &g->clk_pmu.avfs_vinobjs;
254
255 BOARDOBJGRP_PMU_CONSTRUCT(pboardobjgrp, CLK, VIN_DEVICE);
256
257 status = BOARDOBJGRP_PMU_CMD_GRP_SET_CONSTRUCT(g, pboardobjgrp,
258 clk, CLK, clk_vin_device, CLK_VIN_DEVICE);
259 if (status) {
260 gk20a_err(dev_from_gk20a(g),
261 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
262 status);
263 goto done;
264 }
265
266 pboardobjgrp->pmudatainit = _clk_vin_devgrp_pmudatainit_super;
267 pboardobjgrp->pmudatainstget = _clk_vin_devgrp_pmudata_instget;
268 pboardobjgrp->pmustatusinstget = _clk_vin_devgrp_pmustatus_instget;
269
270 status = devinit_get_vin_device_table(g, &g->clk_pmu.avfs_vinobjs);
271 if (status)
272 goto done;
273
274 /*update vin calibration to fuse */
275 if (pvinobjs->calibration_rev_vbios == read_vin_cal_fuse_rev(g)) {
276 BOARDOBJGRP_FOR_EACH(&(pvinobjs->super.super),
277 struct vin_device *, pvindev, i) {
278 slope = 0;
279 intercept = 0;
280 pvindev = CLK_GET_VIN_DEVICE(pvinobjs, i);
281 status = read_vin_cal_slope_intercept_fuse(g,
282 pvindev->id, &slope, &intercept);
283 if (status) {
284 gk20a_err(dev_from_gk20a(g),
285 "err reading vin cal for id %x", pvindev->id);
286 goto done;
287 }
288 if (slope != 0 && intercept != 0) {
289 pvindev->slope = slope;
290 pvindev->intercept = intercept;
291 }
292 }
293 }
294 status = BOARDOBJGRP_PMU_CMD_GRP_GET_STATUS_CONSTRUCT(g,
295 &g->clk_pmu.avfs_vinobjs.super.super,
296 clk, CLK, clk_vin_device, CLK_VIN_DEVICE);
297 if (status) {
298 gk20a_err(dev_from_gk20a(g),
299 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
300 status);
301 goto done;
302 }
303
304done:
305 gk20a_dbg_info(" done status %x", status);
306 return status;
307}
308
309u32 clk_vin_pmu_setup(struct gk20a *g)
310{
311 u32 status;
312 struct boardobjgrp *pboardobjgrp = NULL;
313
314 gk20a_dbg_info("");
315
316 pboardobjgrp = &g->clk_pmu.avfs_vinobjs.super.super;
317
318 if (!pboardobjgrp->bconstructed)
319 return -EINVAL;
320
321 status = pboardobjgrp->pmuinithandle(g, pboardobjgrp);
322
323 gk20a_dbg_info("Done");
324 return status;
325}
326
327static u32 devinit_get_vin_device_table(struct gk20a *g,
328 struct avfsvinobjs *pvinobjs)
329{
330 u32 status = 0;
331 u8 *vin_table_ptr = NULL;
332 struct vin_descriptor_header_10 vin_desc_table_header = { 0 };
333 struct vin_descriptor_entry_10 vin_desc_table_entry = { 0 };
334 u8 *vin_tbl_entry_ptr = NULL;
335 u32 index = 0;
336 u32 slope, intercept;
337 struct vin_device vin_dev_data;
338 struct vin_device *pvin_dev;
339
340 gk20a_dbg_info("");
341
342 if (g->ops.bios.get_perf_table_ptrs) {
343 vin_table_ptr = (u8 *)g->ops.bios.get_perf_table_ptrs(g,
344 g->bios.clock_token, VIN_TABLE);
345 if (vin_table_ptr == NULL) {
346 status = -1;
347 goto done;
348 }
349 }
350
351 memcpy(&vin_desc_table_header, vin_table_ptr,
352 sizeof(struct vin_descriptor_header_10));
353
354 pvinobjs->calibration_rev_vbios =
355 BIOS_GET_FIELD(vin_desc_table_header.flags0,
356 NV_VIN_DESC_FLAGS0_VIN_CAL_REVISION);
357 pvinobjs->vin_is_disable_allowed =
358 BIOS_GET_FIELD(vin_desc_table_header.flags0,
359 NV_VIN_DESC_FLAGS0_DISABLE_CONTROL);
360
361 /* VIN calibration slope: XX.YYY mV/code => XXYYY uV/code*/
362 slope = ((BIOS_GET_FIELD(vin_desc_table_header.vin_cal,
363 NV_VIN_DESC_VIN_CAL_SLOPE_INTEGER) * 1000)) +
364 ((BIOS_GET_FIELD(vin_desc_table_header.vin_cal,
365 NV_VIN_DESC_VIN_CAL_SLOPE_FRACTION)));
366
367 /* VIN calibration intercept: ZZZ.W mV => ZZZW00 uV */
368 intercept = ((BIOS_GET_FIELD(vin_desc_table_header.vin_cal,
369 NV_VIN_DESC_VIN_CAL_INTERCEPT_INTEGER) * 1000)) +
370 ((BIOS_GET_FIELD(vin_desc_table_header.vin_cal,
371 NV_VIN_DESC_VIN_CAL_INTERCEPT_FRACTION) * 100));
372
373 /* Read table entries*/
374 vin_tbl_entry_ptr = vin_table_ptr + vin_desc_table_header.header_sizee;
375 for (index = 0; index < vin_desc_table_header.entry_count; index++) {
376 u32 vin_id;
377
378 memcpy(&vin_desc_table_entry, vin_tbl_entry_ptr,
379 sizeof(struct vin_descriptor_entry_10));
380
381 if (vin_desc_table_entry.vin_device_type == CTRL_CLK_VIN_TYPE_DISABLED)
382 continue;
383
384 vin_id = vin_desc_table_entry.vin_device_id;
385
386 vin_dev_data.super.type =
387 (u8)vin_desc_table_entry.vin_device_type;
388 vin_dev_data.id = (u8)vin_desc_table_entry.vin_device_id;
389 vin_dev_data.volt_domain_vbios =
390 (u8)vin_desc_table_entry.volt_domain_vbios;
391 vin_dev_data.slope = slope;
392 vin_dev_data.intercept = intercept;
393
394 vin_dev_data.flls_shared_mask = 0;
395
396 pvin_dev = construct_vin_device(g, (void *)&vin_dev_data);
397
398 status = boardobjgrp_objinsert(&pvinobjs->super.super,
399 (struct boardobj *)pvin_dev, index);
400
401 vin_tbl_entry_ptr += vin_desc_table_header.entry_size;
402 }
403
404done:
405 gk20a_dbg_info(" done status %x", status);
406 return status;
407}
408
409static struct vin_device *construct_vin_device(struct gk20a *g, void *pargs)
410{
411 struct boardobj *board_obj_ptr = NULL;
412 struct vin_device *pvin_dev;
413 struct vin_device *board_obj_vin_ptr = NULL;
414 u32 status;
415
416 gk20a_dbg_info("");
417 status = boardobj_construct_super(g, &board_obj_ptr,
418 sizeof(struct vin_device), pargs);
419 if (status)
420 return NULL;
421
422 /*got vin board obj allocated now fill it into boardobj grp*/
423 pvin_dev = (struct vin_device *)pargs;
424 board_obj_vin_ptr = (struct vin_device *)board_obj_ptr;
425 /* override super class interface */
426 board_obj_ptr->pmudatainit = vin_device_init_pmudata_super;
427 board_obj_vin_ptr->id = pvin_dev->id;
428 board_obj_vin_ptr->volt_domain_vbios = pvin_dev->volt_domain_vbios;
429 board_obj_vin_ptr->slope = pvin_dev->slope;
430 board_obj_vin_ptr->intercept = pvin_dev->intercept;
431 board_obj_vin_ptr->flls_shared_mask = pvin_dev->flls_shared_mask;
432 board_obj_vin_ptr->volt_domain = CTRL_VOLT_DOMAIN_LOGIC;
433
434 gk20a_dbg_info(" Done");
435
436 return (struct vin_device *)board_obj_ptr;
437}
438
439static u32 vin_device_init_pmudata_super(struct gk20a *g,
440 struct boardobj *board_obj_ptr,
441 struct nv_pmu_boardobj *ppmudata)
442{
443 u32 status = 0;
444 struct vin_device *pvin_dev;
445 struct nv_pmu_clk_clk_vin_device_boardobj_set *perf_pmu_data;
446
447 gk20a_dbg_info("");
448
449 status = boardobj_pmudatainit_super(g, board_obj_ptr, ppmudata);
450 if (status != 0)
451 return status;
452
453 pvin_dev = (struct vin_device *)board_obj_ptr;
454 perf_pmu_data = (struct nv_pmu_clk_clk_vin_device_boardobj_set *)
455 ppmudata;
456
457 perf_pmu_data->id = pvin_dev->id;
458 perf_pmu_data->intercept = pvin_dev->intercept;
459 perf_pmu_data->volt_domain = pvin_dev->volt_domain;
460 perf_pmu_data->slope = pvin_dev->slope;
461 perf_pmu_data->flls_shared_mask = pvin_dev->flls_shared_mask;
462
463 gk20a_dbg_info(" Done");
464
465 return status;
466}
diff --git a/drivers/gpu/nvgpu/clk/clk_vin.h b/drivers/gpu/nvgpu/clk/clk_vin.h
new file mode 100644
index 00000000..1ffd7971
--- /dev/null
+++ b/drivers/gpu/nvgpu/clk/clk_vin.h
@@ -0,0 +1,56 @@
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#ifndef _CLKVIN_H_
15#define _CLKVIN_H_
16
17#include "boardobj/boardobj.h"
18#include "boardobj/boardobjgrp.h"
19#include "clk.h"
20
21struct vin_device;
22struct clk_pmupstate;
23
24struct avfsvinobjs {
25 struct boardobjgrp_e32 super;
26 u8 calibration_rev_vbios;
27 u8 calibration_rev_fused;
28 bool vin_is_disable_allowed;
29};
30typedef u32 vin_device_state_load(struct gk20a *g,
31 struct clk_pmupstate *clk, struct vin_device *pdev);
32
33struct vin_device {
34 struct boardobj super;
35 u8 id;
36 u8 volt_domain;
37 u8 volt_domain_vbios;
38 u32 slope;
39 u32 intercept;
40 u32 flls_shared_mask;
41
42 vin_device_state_load *state_load;
43};
44
45/* get vin device object from descriptor table index*/
46#define CLK_GET_VIN_DEVICE(pvinobjs, dev_index) \
47 ((struct vin_device *)BOARDOBJGRP_OBJ_GET_BY_IDX( \
48 ((struct boardobjgrp *)&(pvinobjs->super.super)), (dev_index)))
49
50boardobj_construct construct_vindevice;
51boardobj_pmudatainit vindeviceinit_pmudata_super;
52
53u32 clk_vin_sw_setup(struct gk20a *g);
54u32 clk_vin_pmu_setup(struct gk20a *g);
55
56#endif