summaryrefslogtreecommitdiffstats
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
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
-rw-r--r--drivers/gpu/nvgpu/Makefile.nvgpu-t18x12
-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
-rw-r--r--drivers/gpu/nvgpu/gp106/hal_gp106.c2
-rw-r--r--drivers/gpu/nvgpu/gp106/hw_fuse_gp106.h88
-rw-r--r--drivers/gpu/nvgpu/gp10b/hal_gp10b.c2
-rw-r--r--drivers/gpu/nvgpu/include/bios.h411
-rw-r--r--drivers/gpu/nvgpu/perf/perf.c98
-rw-r--r--drivers/gpu/nvgpu/perf/perf.h60
-rw-r--r--drivers/gpu/nvgpu/perf/vfe_equ.c590
-rw-r--r--drivers/gpu/nvgpu/perf/vfe_equ.h76
-rw-r--r--drivers/gpu/nvgpu/perf/vfe_var.c1048
-rw-r--r--drivers/gpu/nvgpu/perf/vfe_var.h97
-rw-r--r--drivers/gpu/nvgpu/pstate/pstate.c101
-rw-r--r--drivers/gpu/nvgpu/pstate/pstate.h19
25 files changed, 6201 insertions, 3 deletions
diff --git a/drivers/gpu/nvgpu/Makefile.nvgpu-t18x b/drivers/gpu/nvgpu/Makefile.nvgpu-t18x
index 3e54a989..c6b6f0d2 100644
--- a/drivers/gpu/nvgpu/Makefile.nvgpu-t18x
+++ b/drivers/gpu/nvgpu/Makefile.nvgpu-t18x
@@ -28,7 +28,17 @@ nvgpu-y += \
28 $(nvgpu-t18x)/gp106/sec2_gp106.o \ 28 $(nvgpu-t18x)/gp106/sec2_gp106.o \
29 $(nvgpu-t18x)/gp106/fifo_gp106.o \ 29 $(nvgpu-t18x)/gp106/fifo_gp106.o \
30 $(nvgpu-t18x)/gp106/ltc_gp106.o \ 30 $(nvgpu-t18x)/gp106/ltc_gp106.o \
31 $(nvgpu-t18x)/clk/clk_mclk.o 31 $(nvgpu-t18x)/clk/clk_mclk.o \
32 $(nvgpu-t18x)/pstate/pstate.o \
33 $(nvgpu-t18x)/clk/clk_vin.o \
34 $(nvgpu-t18x)/clk/clk_fll.o \
35 $(nvgpu-t18x)/clk/clk_domain.o \
36 $(nvgpu-t18x)/clk/clk_prog.o \
37 $(nvgpu-t18x)/clk/clk_vf_point.o \
38 $(nvgpu-t18x)/perf/vfe_var.o \
39 $(nvgpu-t18x)/perf/vfe_equ.o \
40 $(nvgpu-t18x)/perf/perf.o \
41 $(nvgpu-t18x)/clk/clk.o
32 42
33nvgpu-$(CONFIG_TEGRA_GK20A) += $(nvgpu-t18x)/gp10b/platform_gp10b_tegra.o 43nvgpu-$(CONFIG_TEGRA_GK20A) += $(nvgpu-t18x)/gp10b/platform_gp10b_tegra.o
34 44
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
diff --git a/drivers/gpu/nvgpu/gp106/hal_gp106.c b/drivers/gpu/nvgpu/gp106/hal_gp106.c
index a52fab7b..822591ed 100644
--- a/drivers/gpu/nvgpu/gp106/hal_gp106.c
+++ b/drivers/gpu/nvgpu/gp106/hal_gp106.c
@@ -144,7 +144,7 @@ int gp106_init_hal(struct gk20a *g)
144 144
145 gops->privsecurity = 1; 145 gops->privsecurity = 1;
146 gops->securegpccs = 1; 146 gops->securegpccs = 1;
147 147 gops->pmupstate = true;
148 gp10b_init_mc(gops); 148 gp10b_init_mc(gops);
149 gp106_init_gr(gops); 149 gp106_init_gr(gops);
150 gp106_init_ltc(gops); 150 gp106_init_ltc(gops);
diff --git a/drivers/gpu/nvgpu/gp106/hw_fuse_gp106.h b/drivers/gpu/nvgpu/gp106/hw_fuse_gp106.h
index 0d4c0362..afabc943 100644
--- a/drivers/gpu/nvgpu/gp106/hw_fuse_gp106.h
+++ b/drivers/gpu/nvgpu/gp106/hw_fuse_gp106.h
@@ -126,4 +126,92 @@ static inline u32 fuse_status_opt_fbp_idx_v(u32 r, u32 i)
126{ 126{
127 return (r >> (0 + i*0)) & 0x1; 127 return (r >> (0 + i*0)) & 0x1;
128} 128}
129static inline u32 fuse_vin_cal_fuse_rev_r(void)
130{
131 return 0x0002164c;
132}
133static inline u32 fuse_vin_cal_fuse_rev_v(u32 r)
134{
135 return 0x3 & r;
136}
137static inline u32 fuse_vin_cal_gpc0_r(void)
138{
139 return 0x00021650;
140}
141static inline u32 fuse_vin_cal_gpc0_icpt_data_v(u32 r)
142{
143 return ((r & 0xFFFC000) >> 14);
144}
145static inline u32 fuse_vin_cal_gpc0_icpt_frac_size_v(void)
146{
147 return 2;
148}
149static inline u32 fuse_vin_cal_gpc0_slope_data_v(u32 r)
150{
151 return (r & 0x3FFF);
152}
153static inline u32 fuse_vin_cal_gpc0_slope_frac_size_v(void)
154{
155 return 10;
156}
157static inline u32 fuse_vin_cal_gpc1_delta_r(void)
158{
159 return 0x00021654;
160}
161static inline u32 fuse_vin_cal_gpc1_icpt_sign_f(void)
162{
163 return 0x400000;
164}
165static inline u32 fuse_vin_cal_gpc1_slope_sign_f(void)
166{
167 return 0x8000;
168}
169static inline u32 fuse_vin_cal_gpc1_icpt_data_v(u32 r)
170{
171 return ((r & 0x3FF000) >> 12);
172}
173static inline u32 fuse_vin_cal_gpc1_icpt_frac_size_v(void)
174{
175 return 2;
176}
177static inline u32 fuse_vin_cal_gpc1_slope_data_v(u32 r)
178{
179 return (r & 0x7FF);
180}
181static inline u32 fuse_vin_cal_gpc1_slope_frac_size_v(void)
182{
183 return 10;
184}
185static inline u32 fuse_vin_cal_gpc2_delta_r(void)
186{
187 return 0x00021658;
188}
189static inline u32 fuse_vin_cal_gpc3_delta_r(void)
190{
191 return 0x0002165c;
192}
193static inline u32 fuse_vin_cal_gpc4_delta_r(void)
194{
195 return 0x00021660;
196}
197static inline u32 fuse_vin_cal_gpc5_delta_r(void)
198{
199 return 0x00021664;
200}
201static inline u32 fuse_vin_cal_shared_delta_r(void)
202{
203 return 0x00021668;
204}
205static inline u32 fuse_vin_cal_sram_delta_r(void)
206{
207 return 0x0002166c;
208}
209static inline u32 fuse_vin_cal_sram_icpt_data_v(u32 r)
210{
211 return ((r & 0x3FF000) >> 12);
212}
213static inline u32 fuse_vin_cal_sram_icpt_frac_size_v(void)
214{
215 return 1;
216}
129#endif 217#endif
diff --git a/drivers/gpu/nvgpu/gp10b/hal_gp10b.c b/drivers/gpu/nvgpu/gp10b/hal_gp10b.c
index c4e44483..2699dd7a 100644
--- a/drivers/gpu/nvgpu/gp10b/hal_gp10b.c
+++ b/drivers/gpu/nvgpu/gp10b/hal_gp10b.c
@@ -193,7 +193,7 @@ int gp10b_init_hal(struct gk20a *g)
193 u32 val; 193 u32 val;
194 194
195 *gops = gp10b_ops; 195 *gops = gp10b_ops;
196 196 gops->pmupstate = false;
197#ifdef CONFIG_TEGRA_ACR 197#ifdef CONFIG_TEGRA_ACR
198 if (platform->is_fmodel) { 198 if (platform->is_fmodel) {
199 gops->privsecurity = 0; 199 gops->privsecurity = 0;
diff --git a/drivers/gpu/nvgpu/include/bios.h b/drivers/gpu/nvgpu/include/bios.h
new file mode 100644
index 00000000..3af5bcf4
--- /dev/null
+++ b/drivers/gpu/nvgpu/include/bios.h
@@ -0,0 +1,411 @@
1/*
2 * vbios tables support
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
16#ifndef NVGPU_INCLUDE_BIOS_H
17#define NVGPU_INCLUDE_BIOS_H
18
19#include "gk20a/gk20a.h"
20
21#define BIOS_GET_FIELD(value, name) ((value & name##_MASK) >> name##_SHIFT)
22
23struct fll_descriptor_header {
24 u8 version;
25 u8 size;
26} __packed;
27
28#define FLL_DESCRIPTOR_HEADER_10_SIZE_4 4
29#define FLL_DESCRIPTOR_HEADER_10_SIZE_6 6
30
31struct fll_descriptor_header_10 {
32 u8 version;
33 u8 header_size;
34 u8 entry_size;
35 u8 entry_count;
36 u16 max_min_freq_mhz;
37} __packed;
38
39#define FLL_DESCRIPTOR_ENTRY_10_SIZE 15
40
41struct fll_descriptor_entry_10 {
42 u8 fll_device_type;
43 u8 clk_domain;
44 u8 fll_device_id;
45 u16 lut_params;
46 u8 vin_idx_logic;
47 u8 vin_idx_sram;
48 u16 fll_params;
49 u8 min_freq_vfe_idx;
50 u8 freq_ctrl_idx;
51 u16 ref_freq_mhz;
52 u16 ffr_cutoff_freq_mhz;
53} __packed;
54
55#define NV_FLL_DESC_FLL_PARAMS_MDIV_MASK 0x1F
56#define NV_FLL_DESC_FLL_PARAMS_MDIV_SHIFT 0
57
58#define NV_FLL_DESC_LUT_PARAMS_VSELECT_MASK 0x3
59#define NV_FLL_DESC_LUT_PARAMS_VSELECT_SHIFT 0
60
61#define NV_FLL_DESC_LUT_PARAMS_HYSTERISIS_THRESHOLD_MASK 0x3C
62#define NV_FLL_DESC_LUT_PARAMS_HYSTERISIS_THRESHOLD_SHIFT 2
63
64struct vin_descriptor_header_10 {
65 u8 version;
66 u8 header_sizee;
67 u8 entry_size;
68 u8 entry_count;
69 u8 flags0;
70 u32 vin_cal;
71} __packed;
72
73struct vin_descriptor_entry_10 {
74 u8 vin_device_type;
75 u8 volt_domain_vbios;
76 u8 vin_device_id;
77} __packed;
78
79#define NV_VIN_DESC_FLAGS0_VIN_CAL_REVISION_MASK 0x7
80#define NV_VIN_DESC_FLAGS0_VIN_CAL_REVISION_SHIFT 0
81
82#define NV_VIN_DESC_FLAGS0_DISABLE_CONTROL_MASK 0x8
83#define NV_VIN_DESC_FLAGS0_DISABLE_CONTROL_SHIFT 3
84
85#define NV_VIN_DESC_VIN_CAL_SLOPE_FRACTION_MASK 0x1FF
86#define NV_VIN_DESC_VIN_CAL_SLOPE_FRACTION_SHIFT 0
87
88#define NV_VIN_DESC_VIN_CAL_SLOPE_INTEGER_MASK 0x3C00
89#define NV_VIN_DESC_VIN_CAL_SLOPE_INTEGER_SHIFT 10
90
91#define NV_VIN_DESC_VIN_CAL_INTERCEPT_FRACTION_MASK 0x3C000
92#define NV_VIN_DESC_VIN_CAL_INTERCEPT_FRACTION_SHIFT 14
93
94#define NV_VIN_DESC_VIN_CAL_INTERCEPT_INTEGER_MASK 0xFFC0000
95#define NV_VIN_DESC_VIN_CAL_INTERCEPT_INTEGER_SHIFT 18
96
97#define VBIOS_CLOCKS_TABLE_1X_HEADER_SIZE_07 0x07
98struct vbios_clocks_table_1x_header {
99 u8 version;
100 u8 header_size;
101 u8 entry_size;
102 u8 entry_count;
103 u8 clocks_hal;
104 u16 cntr_sampling_periodms;
105} __packed;
106
107#define VBIOS_CLOCKS_TABLE_1X_ENTRY_SIZE_09 0x09
108struct vbios_clocks_table_1x_entry {
109 u8 flags0;
110 u16 param0;
111 u32 param1;
112 u16 param2;
113} __packed;
114
115#define NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_FLAGS0_USAGE_MASK 0x1F
116#define NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_FLAGS0_USAGE_SHIFT 0
117#define NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_FLAGS0_USAGE_FIXED 0x00
118#define NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_FLAGS0_USAGE_MASTER 0x01
119#define NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_FLAGS0_USAGE_SLAVE 0x02
120
121#define NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM0_PROG_CLK_PROG_IDX_FIRST_MASK 0xFF
122#define NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM0_PROG_CLK_PROG_IDX_FIRST_SHIFT 0
123#define NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM0_PROG_CLK_PROG_IDX_LAST_MASK 0xFF00
124#define NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM0_PROG_CLK_PROG_IDX_LAST_SHIFT 0x08
125
126#define NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM1_FIXED_FREQUENCY_MHZ_MASK 0xFFFF
127#define NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM1_FIXED_FREQUENCY_MHZ_SHIFT 0
128#define NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM1_MASTER_FREQ_OC_DELTA_MIN_MHZ_MASK 0xFFFF
129#define NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM1_MASTER_FREQ_OC_DELTA_MIN_MHZ_SHIFT 0
130
131#define NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM1_MASTER_FREQ_OC_DELTA_MAX_MHZ_MASK 0xFFFF0000
132#define NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM1_MASTER_FREQ_OC_DELTA_MAX_MHZ_SHIFT 0
133
134#define NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM1_SLAVE_MASTER_DOMAIN_MASK 0xF
135#define NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM1_SLAVE_MASTER_DOMAIN_SHIFT 0
136
137#define NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM2_PROG_NOISE_UNAWARE_ORDERING_IDX_MASK 0xF
138#define NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM2_PROG_NOISE_UNAWARE_ORDERING_IDX_SHIFT 0
139
140#define NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM2_PROG_NOISE_AWARE_ORDERING_IDX_MASK 0xF0
141#define NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM2_PROG_NOISE_AWARE_ORDERING_IDX_SHIFT 4
142
143#define NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM2_PROG_FORCE_NOISE_UNAWARE_ORDERING_MASK 0x100
144#define NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM2_PROG_FORCE_NOISE_UNAWARE_ORDERING_SHIFT 8
145#define NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM2_PROG_FORCE_NOISE_UNAWARE_ORDERING_FALSE 0x00
146#define NV_VBIOS_CLOCKS_TABLE_1X_ENTRY_PARAM2_PROG_FORCE_NOISE_UNAWARE_ORDERING_TRUE 0x01
147
148#define VBIOS_CLOCK_PROGRAMMING_TABLE_1X_HEADER_SIZE_08 0x08
149struct vbios_clock_programming_table_1x_header {
150 u8 version;
151 u8 header_size;
152 u8 entry_size;
153 u8 entry_count;
154 u8 slave_entry_size;
155 u8 slave_entry_count;
156 u8 vf_entry_size;
157 u8 vf_entry_count;
158} __packed;
159
160#define VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_SIZE_05 0x05
161#define VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_SIZE_0D 0x0D
162struct vbios_clock_programming_table_1x_entry {
163 u8 flags0;
164 u16 freq_max_mhz;
165 u8 param0;
166 u8 param1;
167 u32 rsvd;
168 u32 rsvd1;
169} __packed;
170
171#define NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE_MASK 0xF
172#define NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE_SHIFT 0
173#define NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE_MASTER_RATIO 0x00
174#define NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE_MASTER_TABLE 0x01
175#define NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_TYPE_SLAVE 0x02
176
177#define NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_SOURCE_MASK 0x70
178#define NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_SOURCE_SHIFT 4
179#define NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_SOURCE_PLL 0x00
180#define NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_SOURCE_ONE_SOURCE 0x01
181#define NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_SOURCE_FLL 0x02
182
183#define NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_OVOC_ENABLED_MASK 0x80
184#define NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_OVOC_ENABLED_SHIFT 7
185#define NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_OVOC_ENABLED_FALSE 0x00
186#define NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_FLAGS0_OVOC_ENABLED_TRUE 0x01
187
188#define NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_PARAM0_PLL_PLL_INDEX_MASK 0xFF
189#define NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_PARAM0_PLL_PLL_INDEX_SHIFT 0
190
191#define NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_PARAM1_PLL_FREQ_STEP_SIZE_MASK 0xFF
192#define NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_ENTRY_PARAM1_PLL_FREQ_STEP_SIZE_SHIFT 0
193
194#define VBIOS_CLOCK_PROGRAMMING_TABLE_1X_SLAVE_ENTRY_SIZE_03 0x03
195struct vbios_clock_programming_table_1x_slave_entry {
196 u8 clk_dom_idx;
197 u16 param0;
198} __packed;
199
200#define NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_SLAVE_ENTRY_PARAM0_MASTER_RATIO_RATIO_MASK 0xFF
201#define NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_SLAVE_ENTRY_PARAM0_MASTER_RATIO_RATIO_SHIFT 0
202
203#define NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_SLAVE_ENTRY_PARAM0_MASTER_TABLE_FREQ_MASK 0x3FFF
204#define NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_SLAVE_ENTRY_PARAM0_MASTER_TABLE_FREQ_SHIFT 0
205
206#define VBIOS_CLOCK_PROGRAMMING_TABLE_1X_VF_ENTRY_SIZE_02 0x02
207struct vbios_clock_programming_table_1x_vf_entry {
208 u8 vfe_idx;
209 u8 param0;
210} __packed;
211
212#define NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_VF_ENTRY_PARAM0_FLL_GAIN_VFE_IDX_MASK 0xFF
213#define NV_VBIOS_CLOCK_PROGRAMMING_TABLE_1X_VF_ENTRY_PARAM0_FLL_GAIN_VFE_IDX_SHIFT 0
214
215struct vbios_vfe_3x_header_struct {
216 u8 version;
217 u8 header_size;
218 u8 vfe_var_entry_size;
219 u8 vfe_var_entry_count;
220 u8 vfe_equ_entry_size;
221 u8 vfe_equ_entry_count;
222 u8 polling_periodms;
223} __packed;
224
225#define VBIOS_VFE_3X_VAR_ENTRY_SIZE_11 0x11
226#define VBIOS_VFE_3X_VAR_ENTRY_SIZE_19 0x19
227struct vbios_vfe_3x_var_entry_struct {
228 u8 type;
229 u32 out_range_min;
230 u32 out_range_max;
231 u32 param0;
232 u32 param1;
233 u32 param2;
234 u32 param3;
235} __packed;
236
237#define VBIOS_VFE_3X_VAR_ENTRY_TYPE_DISABLED 0x00
238#define VBIOS_VFE_3X_VAR_ENTRY_TYPE_SINGLE_FREQUENCY 0x01
239#define VBIOS_VFE_3X_VAR_ENTRY_TYPE_SINGLE_VOLTAGE 0x02
240#define VBIOS_VFE_3X_VAR_ENTRY_TYPE_SINGLE_SENSED_TEMP 0x03
241#define VBIOS_VFE_3X_VAR_ENTRY_TYPE_SINGLE_SENSED_FUSE 0x04
242#define VBIOS_VFE_3X_VAR_ENTRY_TYPE_DERIVED_PRODUCT 0x05
243#define VBIOS_VFE_3X_VAR_ENTRY_TYPE_DERIVED_SUM 0x06
244
245#define VBIOS_VFE_3X_VAR_ENTRY_PAR0_SSTEMP_TH_CH_IDX_MASK 0xFF
246#define VBIOS_VFE_3X_VAR_ENTRY_PAR0_SSTEMP_TH_CH_IDX_SHIFT 0
247
248#define VBIOS_VFE_3X_VAR_ENTRY_PAR0_SSTEMP_HYS_POS_MASK 0xFF00
249#define VBIOS_VFE_3X_VAR_ENTRY_PAR0_SSTEMP_HYS_POS_SHIFT 8
250
251#define VBIOS_VFE_3X_VAR_ENTRY_PAR0_SSTEMP_HYS_NEG_MASK 0xFF0000
252#define VBIOS_VFE_3X_VAR_ENTRY_PAR0_SSTEMP_HYS_NEG_SHIFT 16
253
254#define VBIOS_VFE_3X_VAR_ENTRY_PAR0_SSFUSE_VFIELD_ID_MASK 0xFF
255#define VBIOS_VFE_3X_VAR_ENTRY_PAR0_SSFUSE_VFIELD_ID_SHIFT 0
256
257#define VBIOS_VFE_3X_VAR_ENTRY_PAR0_SSFUSE_VFIELD_ID_VER_MASK 0xFF00
258#define VBIOS_VFE_3X_VAR_ENTRY_PAR0_SSFUSE_VFIELD_ID_VER_SHIFT 8
259
260#define VBIOS_VFE_3X_VAR_ENTRY_PAR0_SSFUSE_EXPECTED_VER_MASK 0xFF0000
261#define VBIOS_VFE_3X_VAR_ENTRY_PAR0_SSFUSE_EXPECTED_VER_SHIFT 16
262
263#define VBIOS_VFE_3X_VAR_ENTRY_PAR0_SSFUSE_USE_DEFAULT_ON_VER_CHECK_FAIL_MASK 0x1000000
264#define VBIOS_VFE_3X_VAR_ENTRY_PAR0_SSFUSE_USE_DEFAULT_ON_VER_CHECK_FAIL_SHIFT 24
265
266#define VBIOS_VFE_3X_VAR_ENTRY_PAR0_SSFUSE_USE_DEFAULT_ON_VER_CHECK_FAIL_YES 0x00000001
267#define VBIOS_VFE_3X_VAR_ENTRY_PAR0_SSFUSE_USE_DEFAULT_ON_VER_CHECK_FAIL_NO 0x00000000
268#define VBIOS_VFE_3X_VAR_ENTRY_PAR0_DPROD_VFE_VAR_IDX_0_MASK 0xFF
269#define VBIOS_VFE_3X_VAR_ENTRY_PAR0_DPROD_VFE_VAR_IDX_0_SHIFT 0
270
271#define VBIOS_VFE_3X_VAR_ENTRY_PAR0_DPROD_VFE_VAR_IDX_1_MASK 0xFF00
272#define VBIOS_VFE_3X_VAR_ENTRY_PAR0_DPROD_VFE_VAR_IDX_1_SHIFT 8
273
274#define VBIOS_VFE_3X_VAR_ENTRY_PAR0_DSUM_VFE_VAR_IDX_0_MASK 0xFF
275#define VBIOS_VFE_3X_VAR_ENTRY_PAR0_DSUM_VFE_VAR_IDX_0_SHIFT 0
276
277#define VBIOS_VFE_3X_VAR_ENTRY_PAR0_DSUM_VFE_VAR_IDX_1_MASK 0xFF00
278#define VBIOS_VFE_3X_VAR_ENTRY_PAR0_DSUM_VFE_VAR_IDX_1_SHIFT 8
279
280#define VBIOS_VFE_3X_VAR_ENTRY_PAR1_SSFUSE_DEFAULT_VAL_MASK 0xFFFFFFFF
281#define VBIOS_VFE_3X_VAR_ENTRY_PAR1_SSFUSE_DEFAULT_VAL_SHIFT 0
282
283#define VBIOS_VFE_3X_VAR_ENTRY_PAR1_SSFUSE_HW_CORRECTION_SCALE_MASK 0xFFFFFFFF
284#define VBIOS_VFE_3X_VAR_ENTRY_PAR1_SSFUSE_HW_CORRECTION_SCALE_SHIFT 0
285
286#define VBIOS_VFE_3X_VAR_ENTRY_PAR1_SSFUSE_HW_CORRECTION_OFFSET_MASK 0xFFFFFFFF
287#define VBIOS_VFE_3X_VAR_ENTRY_PAR1_SSFUSE_HW_CORRECTION_OFFSET_SHIFT 0
288
289#define VBIOS_VFE_3X_EQU_ENTRY_SIZE_17 0x17
290#define VBIOS_VFE_3X_EQU_ENTRY_SIZE_18 0x18
291
292struct vbios_vfe_3x_equ_entry_struct {
293 u8 type;
294 u8 var_idx;
295 u8 equ_idx_next;
296 u32 out_range_min;
297 u32 out_range_max;
298 u32 param0;
299 u32 param1;
300 u32 param2;
301 u8 param3;
302} __packed;
303
304
305#define VBIOS_VFE_3X_EQU_ENTRY_TYPE_DISABLED 0x00
306#define VBIOS_VFE_3X_EQU_ENTRY_TYPE_QUADRATIC 0x01
307#define VBIOS_VFE_3X_EQU_ENTRY_TYPE_MINMAX 0x02
308#define VBIOS_VFE_3X_EQU_ENTRY_TYPE_COMPARE 0x03
309#define VBIOS_VFE_3X_EQU_ENTRY_TYPE_QUADRATIC_FXP 0x04
310#define VBIOS_VFE_3X_EQU_ENTRY_TYPE_MINMAX_FXP 0x05
311
312#define VBIOS_VFE_3X_EQU_ENTRY_IDX_INVALID 0xFF
313
314#define VBIOS_VFE_3X_EQU_ENTRY_PAR0_QUADRATIC_C0_MASK 0xFFFFFFFF
315#define VBIOS_VFE_3X_EQU_ENTRY_PAR0_QUADRATIC_C0_SHIFT 0
316
317#define VBIOS_VFE_3X_EQU_ENTRY_PAR0_MINMAX_VFE_EQU_IDX_0_MASK 0xFF
318#define VBIOS_VFE_3X_EQU_ENTRY_PAR0_MINMAX_VFE_EQU_IDX_0_SHIFT 0
319
320#define VBIOS_VFE_3X_EQU_ENTRY_PAR0_MINMAX_VFE_EQU_IDX_1_MASK 0xFF00
321#define VBIOS_VFE_3X_EQU_ENTRY_PAR0_MINMAX_VFE_EQU_IDX_1_SHIFT 8
322
323#define VBIOS_VFE_3X_EQU_ENTRY_PAR0_MINMAX_CRIT_MASK 0x10000
324#define VBIOS_VFE_3X_EQU_ENTRY_PAR0_MINMAX_CRIT_SHIFT 16
325#define VBIOS_VFE_3X_EQU_ENTRY_PAR0_MINMAX_CRIT_MIN 0x00000000
326#define VBIOS_VFE_3X_EQU_ENTRY_PAR0_MINMAX_CRIT_MAX 0x00000001
327
328#define VBIOS_VFE_3X_EQU_ENTRY_PAR0_COMPARE_CRIT_MASK 0xFFFFFFFF
329#define VBIOS_VFE_3X_EQU_ENTRY_PAR0_COMPARE_CRIT_SHIFT 0
330
331#define VBIOS_VFE_3X_EQU_ENTRY_PAR1_QUADRATIC_C1_MASK 0xFFFFFFFF
332#define VBIOS_VFE_3X_EQU_ENTRY_PAR1_QUADRATIC_C1_SHIFT 0
333
334#define VBIOS_VFE_3X_EQU_ENTRY_PAR1_COMPARE_VFE_EQU_IDX_TRUE_MASK 0xFF
335#define VBIOS_VFE_3X_EQU_ENTRY_PAR1_COMPARE_VFE_EQU_IDX_TRUE_SHIFT 0
336
337#define VBIOS_VFE_3X_EQU_ENTRY_PAR1_COMPARE_VFE_EQU_IDX_FALSE_MASK 0xFF00
338#define VBIOS_VFE_3X_EQU_ENTRY_PAR1_COMPARE_VFE_EQU_IDX_FALSE_SHIFT 8
339
340#define VBIOS_VFE_3X_EQU_ENTRY_PAR1_COMPARE_FUNCTION_MASK 0x70000
341#define VBIOS_VFE_3X_EQU_ENTRY_PAR1_COMPARE_FUNCTION_SHIFT 16
342#define VBIOS_VFE_3X_EQU_ENTRY_PAR1_COMPARE_FUNCTION_EQUAL 0x00000000
343#define VBIOS_VFE_3X_EQU_ENTRY_PAR1_COMPARE_FUNCTION_GREATER_EQ 0x00000001
344#define VBIOS_VFE_3X_EQU_ENTRY_PAR1_COMPARE_FUNCTION_GREATER 0x00000002
345
346#define VBIOS_VFE_3X_EQU_ENTRY_PAR3_OUTPUT_TYPE_MASK 0xF
347#define VBIOS_VFE_3X_EQU_ENTRY_PAR3_OUTPUT_TYPE_SHIFT 0
348#define VBIOS_VFE_3X_EQU_ENTRY_PAR3_OUTPUT_TYPE_UNITLESS 0x0
349#define VBIOS_VFE_3X_EQU_ENTRY_PAR3_OUTPUT_TYPE_FREQ_MHZ 0x1
350#define VBIOS_VFE_3X_EQU_ENTRY_PAR3_OUTPUT_TYPE_VOLT_UV 0x2
351#define VBIOS_VFE_3X_EQU_ENTRY_PAR3_OUTPUT_TYPE_VF_GAIN 0x3
352#define VBIOS_VFE_3X_EQU_ENTRY_PAR3_OUTPUT_TYPE_VOLT_DELTA_UV 0x4
353
354#define NV_VFIELD_DESC_SIZE_BYTE 0x00000000
355#define NV_VFIELD_DESC_SIZE_WORD 0x00000001
356#define NV_VFIELD_DESC_SIZE_DWORD 0x00000002
357#define VFIELD_SIZE(pvregentry) ((pvregentry->strap_reg_desc & 0x18) >> 3)
358
359#define NV_PMU_BIOS_VFIELD_DESC_CODE_INVALID 0x00000000
360#define NV_PMU_BIOS_VFIELD_DESC_CODE_REG 0x00000001
361#define NV_PMU_BIOS_VFIELD_DESC_CODE_INDEX_REG 0x00000002
362
363#define NV_VFIELD_DESC_CODE_INVALID NV_PMU_BIOS_VFIELD_DESC_CODE_INVALID
364#define NV_VFIELD_DESC_CODE_REG NV_PMU_BIOS_VFIELD_DESC_CODE_REG
365#define NV_VFIELD_DESC_CODE_INDEX_REG NV_PMU_BIOS_VFIELD_DESC_CODE_INDEX_REG
366
367#define VFIELD_CODE(pvregentry) ((pvregentry->strap_reg_desc & 0xE0) >> 5)
368
369#define VFIELD_ID_STRAP_IDDQ 0x09
370#define VFIELD_ID_STRAP_IDDQ_1 0x0B
371
372#define VFIELD_REG_HEADER_SIZE 3
373struct vfield_reg_header {
374 u8 version;
375 u8 entry_size;
376 u8 count;
377} __packed;
378
379#define VBIOS_VFIELD_REG_TABLE_VERSION_1_0 0x10
380
381
382#define VFIELD_REG_ENTRY_SIZE 13
383struct vfield_reg_entry {
384 u8 strap_reg_desc;
385 u32 reg;
386 u32 reg_index;
387 u32 index;
388} __packed;
389
390#define VFIELD_HEADER_SIZE 3
391
392struct vfield_header {
393 u8 version;
394 u8 entry_size;
395 u8 count;
396} __packed;
397
398#define VBIOS_VFIELD_TABLE_VERSION_1_0 0x10
399
400#define VFIELD_BIT_START(ventry) (ventry.strap_desc & 0x1F)
401#define VFIELD_BIT_STOP(ventry) ((ventry.strap_desc & 0x3E0) >> 5)
402#define VFIELD_BIT_REG(ventry) ((ventry.strap_desc & 0x3C00) >> 10)
403
404#define VFIELD_ENTRY_SIZE 3
405
406struct vfield_entry {
407 u8 strap_id;
408 u16 strap_desc;
409} __packed;
410
411#endif
diff --git a/drivers/gpu/nvgpu/perf/perf.c b/drivers/gpu/nvgpu/perf/perf.c
new file mode 100644
index 00000000..3821a8dc
--- /dev/null
+++ b/drivers/gpu/nvgpu/perf/perf.c
@@ -0,0 +1,98 @@
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 "perf.h"
16#include "pmuif/gpmuifperf.h"
17#include "pmuif/gpmuifperfvfe.h"
18#include "gk20a/pmu_gk20a.h"
19
20struct perfrpc_pmucmdhandler_params {
21 struct nv_pmu_perf_rpc *prpccall;
22 u32 success;
23};
24
25static void perfrpc_pmucmdhandler(struct gk20a *g, struct pmu_msg *msg,
26 void *param, u32 handle, u32 status)
27{
28 struct perfrpc_pmucmdhandler_params *phandlerparams =
29 (struct perfrpc_pmucmdhandler_params *)param;
30
31 gk20a_dbg_info("");
32
33 if (msg->msg.perf.msg_type != NV_PMU_PERF_MSG_ID_RPC) {
34 gk20a_err(dev_from_gk20a(g),
35 "unsupported msg for VFE LOAD RPC %x",
36 msg->msg.perf.msg_type);
37 return;
38 }
39
40 if (phandlerparams->prpccall->b_supported)
41 phandlerparams->success = 1;
42}
43
44u32 perf_pmu_vfe_load(struct gk20a *g)
45{
46 struct pmu_cmd cmd;
47 struct pmu_msg msg;
48 struct pmu_payload payload = { {0} };
49 u32 status;
50 u32 seqdesc;
51 struct nv_pmu_perf_rpc rpccall = {0};
52 struct perfrpc_pmucmdhandler_params handler = {0};
53
54 rpccall.function = NV_PMU_PERF_RPC_ID_VFE_LOAD;
55 rpccall.params.vfe_load.b_load = true;
56 cmd.hdr.unit_id = PMU_UNIT_PERF;
57 cmd.hdr.size = (u32)sizeof(struct nv_pmu_perf_cmd) +
58 (u32)sizeof(struct pmu_hdr);
59
60 cmd.cmd.perf.cmd_type = NV_PMU_PERF_CMD_ID_RPC;
61 msg.hdr.size = sizeof(struct pmu_msg);
62
63 payload.in.buf = (u8 *)&rpccall;
64 payload.in.size = (u32)sizeof(struct nv_pmu_perf_rpc);
65 payload.in.fb_size = PMU_CMD_SUBMIT_PAYLOAD_PARAMS_FB_SIZE_UNUSED;
66 payload.in.offset = NV_PMU_PERF_CMD_RPC_ALLOC_OFFSET;
67
68 payload.out.buf = (u8 *)&rpccall;
69 payload.out.size = (u32)sizeof(struct nv_pmu_perf_rpc);
70 payload.out.fb_size = PMU_CMD_SUBMIT_PAYLOAD_PARAMS_FB_SIZE_UNUSED;
71 payload.out.offset = NV_PMU_PERF_MSG_RPC_ALLOC_OFFSET;
72
73 handler.prpccall = &rpccall;
74 handler.success = 0;
75
76 status = gk20a_pmu_cmd_post(g, &cmd, NULL, &payload,
77 PMU_COMMAND_QUEUE_LPQ,
78 perfrpc_pmucmdhandler, (void *)&handler,
79 &seqdesc, ~0);
80
81 if (status) {
82 gk20a_err(dev_from_gk20a(g),
83 "unable to post perf RPC cmd %x",
84 cmd.cmd.perf.cmd_type);
85 goto done;
86 }
87
88 pmu_wait_message_cond(&g->pmu,
89 gk20a_get_gr_idle_timeout(g),
90 &handler.success, 1);
91
92 if (handler.success == 0) {
93 status = -EINVAL;
94 gk20a_err(dev_from_gk20a(g), "rpc call to load VFE failed");
95 }
96done:
97 return status;
98}
diff --git a/drivers/gpu/nvgpu/perf/perf.h b/drivers/gpu/nvgpu/perf/perf.h
new file mode 100644
index 00000000..02aed7a6
--- /dev/null
+++ b/drivers/gpu/nvgpu/perf/perf.h
@@ -0,0 +1,60 @@
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#ifndef _PERF_H_
14#define _PERF_H_
15
16#include "vfe_equ.h"
17#include "vfe_var.h"
18#include "gk20a/gk20a.h"
19
20#define CTRL_PERF_VFE_VAR_TYPE_INVALID 0x00
21#define CTRL_PERF_VFE_VAR_TYPE_DERIVED 0x01
22#define CTRL_PERF_VFE_VAR_TYPE_DERIVED_PRODUCT 0x02
23#define CTRL_PERF_VFE_VAR_TYPE_DERIVED_SUM 0x03
24#define CTRL_PERF_VFE_VAR_TYPE_SINGLE 0x04
25#define CTRL_PERF_VFE_VAR_TYPE_SINGLE_FREQUENCY 0x05
26#define CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED 0x06
27#define CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED_FUSE 0x07
28#define CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED_TEMP 0x08
29#define CTRL_PERF_VFE_VAR_TYPE_SINGLE_VOLTAGE 0x09
30
31#define CTRL_PERF_VFE_VAR_SINGLE_OVERRIDE_TYPE_NONE 0x00
32#define CTRL_PERF_VFE_VAR_SINGLE_OVERRIDE_TYPE_VALUE 0x01
33#define CTRL_PERF_VFE_VAR_SINGLE_OVERRIDE_TYPE_OFFSET 0x02
34#define CTRL_PERF_VFE_VAR_SINGLE_OVERRIDE_TYPE_SCALE 0x03
35
36#define CTRL_PERF_VFE_EQU_TYPE_INVALID 0x00
37#define CTRL_PERF_VFE_EQU_TYPE_COMPARE 0x01
38#define CTRL_PERF_VFE_EQU_TYPE_MINMAX 0x02
39#define CTRL_PERF_VFE_EQU_TYPE_QUADRATIC 0x03
40
41#define CTRL_PERF_VFE_EQU_OUTPUT_TYPE_UNITLESS 0x00
42#define CTRL_PERF_VFE_EQU_OUTPUT_TYPE_FREQ_MHZ 0x01
43#define CTRL_PERF_VFE_EQU_OUTPUT_TYPE_VOLT_UV 0x02
44#define CTRL_PERF_VFE_EQU_OUTPUT_TYPE_VF_GAIN 0x03
45#define CTRL_PERF_VFE_EQU_OUTPUT_TYPE_VOLT_DELTA_UV 0x04
46
47#define CTRL_PERF_VFE_EQU_QUADRATIC_COEFF_COUNT 0x03
48
49#define CTRL_PERF_VFE_EQU_COMPARE_FUNCTION_EQUAL 0x00
50#define CTRL_PERF_VFE_EQU_COMPARE_FUNCTION_GREATER_EQ 0x01
51#define CTRL_PERF_VFE_EQU_COMPARE_FUNCTION_GREATER 0x02
52
53struct perf_pmupstate {
54 struct vfe_vars vfe_varobjs;
55 struct vfe_equs vfe_equobjs;
56};
57
58u32 perf_pmu_vfe_load(struct gk20a *g);
59
60#endif
diff --git a/drivers/gpu/nvgpu/perf/vfe_equ.c b/drivers/gpu/nvgpu/perf/vfe_equ.c
new file mode 100644
index 00000000..6630fb21
--- /dev/null
+++ b/drivers/gpu/nvgpu/perf/vfe_equ.c
@@ -0,0 +1,590 @@
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 "perf.h"
16#include "vfe_equ.h"
17#include "include/bios.h"
18#include "boardobj/boardobjgrp.h"
19#include "boardobj/boardobjgrp_e255.h"
20#include "pmuif/gpmuifboardobj.h"
21#include "pmuif/gpmuifperf.h"
22#include "pmuif/gpmuifperfvfe.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 vfe_equ *construct_vfe_equ(struct gk20a *g, void *pargs);
29static u32 devinit_get_vfe_equ_table(struct gk20a *g,
30 struct vfe_equs *pequobjs);
31
32static u32 _vfe_equs_pmudatainit(struct gk20a *g,
33 struct boardobjgrp *pboardobjgrp,
34 struct nv_pmu_boardobjgrp_super *pboardobjgrppmu)
35{
36 u32 status = 0;
37
38 status = boardobjgrp_pmudatainit_e255(g, pboardobjgrp, pboardobjgrppmu);
39 if (status) {
40 gk20a_err(dev_from_gk20a(g),
41 "error updating pmu boardobjgrp for vfe equ 0x%x",
42 status);
43 goto done;
44 }
45
46done:
47 return status;
48}
49
50static u32 _vfe_equs_pmudata_instget(struct gk20a *g,
51 struct nv_pmu_boardobjgrp *pmuboardobjgrp,
52 struct nv_pmu_boardobj **ppboardobjpmudata,
53 u8 idx)
54{
55 struct nv_pmu_perf_vfe_equ_boardobj_grp_set *pgrp_set =
56 (struct nv_pmu_perf_vfe_equ_boardobj_grp_set *)pmuboardobjgrp;
57
58 gk20a_dbg_info("");
59
60 /* check whether pmuboardobjgrp has a valid boardobj in index */
61 if (idx >= CTRL_BOARDOBJGRP_E255_MAX_OBJECTS)
62 return -EINVAL;
63
64 *ppboardobjpmudata = (struct nv_pmu_boardobj *)
65 &pgrp_set->objects[idx].data.board_obj;
66 gk20a_dbg_info(" Done");
67 return 0;
68}
69
70u32 vfe_equ_sw_setup(struct gk20a *g)
71{
72 u32 status;
73 struct boardobjgrp *pboardobjgrp = NULL;
74 struct vfe_equs *pvfeequobjs;
75
76 gk20a_dbg_info("");
77
78 status = boardobjgrpconstruct_e255(&g->perf_pmu.vfe_equobjs.super);
79 if (status) {
80 gk20a_err(dev_from_gk20a(g),
81 "error creating boardobjgrp for clk domain, status - 0x%x",
82 status);
83 goto done;
84 }
85
86 pboardobjgrp = &g->perf_pmu.vfe_equobjs.super.super;
87 pvfeequobjs = &(g->perf_pmu.vfe_equobjs);
88
89 BOARDOBJGRP_PMU_CONSTRUCT(pboardobjgrp, PERF, VFE_EQU);
90
91 status = BOARDOBJGRP_PMU_CMD_GRP_SET_CONSTRUCT(g, pboardobjgrp,
92 perf, PERF, vfe_equ, VFE_EQU);
93 if (status) {
94 gk20a_err(dev_from_gk20a(g),
95 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
96 status);
97 goto done;
98 }
99
100 pboardobjgrp->pmudatainit = _vfe_equs_pmudatainit;
101 pboardobjgrp->pmudatainstget = _vfe_equs_pmudata_instget;
102
103 status = devinit_get_vfe_equ_table(g, pvfeequobjs);
104 if (status)
105 goto done;
106
107done:
108 gk20a_dbg_info(" done status %x", status);
109 return status;
110}
111
112u32 vfe_equ_pmu_setup(struct gk20a *g)
113{
114 u32 status;
115 struct boardobjgrp *pboardobjgrp = NULL;
116
117 gk20a_dbg_info("");
118
119 pboardobjgrp = &g->perf_pmu.vfe_equobjs.super.super;
120
121 if (!pboardobjgrp->bconstructed)
122 return -EINVAL;
123
124 status = pboardobjgrp->pmuinithandle(g, pboardobjgrp);
125
126 gk20a_dbg_info("Done");
127 return status;
128}
129
130static u32 devinit_get_vfe_equ_table(struct gk20a *g,
131 struct vfe_equs *pvfeequobjs)
132{
133 u32 status = 0;
134 u8 *vfeequs_tbl_ptr = NULL;
135 struct vbios_vfe_3x_header_struct vfeequs_tbl_header = { 0 };
136 struct vbios_vfe_3x_equ_entry_struct equ = { 0 };
137 u8 *vfeequs_tbl_entry_ptr = NULL;
138 u8 *rd_offset_ptr = NULL;
139 u32 index = 0;
140 struct vfe_equ *pequ;
141 u8 equ_type = 0;
142 u32 szfmt;
143 union {
144 struct boardobj board_obj;
145 struct vfe_equ super;
146 struct vfe_equ_compare compare;
147 struct vfe_equ_minmax minmax;
148 struct vfe_equ_quadratic quadratic;
149 } equ_data;
150
151 gk20a_dbg_info("");
152
153 if (g->ops.bios.get_perf_table_ptrs) {
154 vfeequs_tbl_ptr = (u8 *)g->ops.bios.get_perf_table_ptrs(g,
155 g->bios.perf_token,
156 CONTINUOUS_VIRTUAL_BINNING_TABLE);
157 if (vfeequs_tbl_ptr == NULL) {
158 status = -EINVAL;
159 goto done;
160 }
161 }
162
163 memcpy(&vfeequs_tbl_header, vfeequs_tbl_ptr,
164 VBIOS_CLOCKS_TABLE_1X_HEADER_SIZE_07);
165 if (vfeequs_tbl_header.header_size != VBIOS_CLOCKS_TABLE_1X_HEADER_SIZE_07) {
166 status = -EINVAL;
167 goto done;
168 }
169
170 if (vfeequs_tbl_header.vfe_equ_entry_size ==
171 VBIOS_VFE_3X_EQU_ENTRY_SIZE_17)
172 szfmt = VBIOS_VFE_3X_EQU_ENTRY_SIZE_17;
173 else if (vfeequs_tbl_header.vfe_equ_entry_size ==
174 VBIOS_VFE_3X_EQU_ENTRY_SIZE_18)
175 szfmt = VBIOS_VFE_3X_EQU_ENTRY_SIZE_18;
176 else {
177 status = -EINVAL;
178 goto done;
179 }
180
181 vfeequs_tbl_entry_ptr = vfeequs_tbl_ptr +
182 vfeequs_tbl_header.header_size +
183 (vfeequs_tbl_header.vfe_var_entry_count *
184 vfeequs_tbl_header.vfe_var_entry_size);
185
186 for (index = 0;
187 index < vfeequs_tbl_header.vfe_equ_entry_count;
188 index++) {
189 memset(&equ, 0, sizeof(struct vbios_vfe_3x_equ_entry_struct));
190
191 rd_offset_ptr = vfeequs_tbl_entry_ptr +
192 (index * vfeequs_tbl_header.vfe_equ_entry_size);
193
194 memcpy(&equ, rd_offset_ptr, szfmt);
195
196 equ_data.super.var_idx = (u8)equ.var_idx;
197 equ_data.super.equ_idx_next =
198 (equ.equ_idx_next == VBIOS_VFE_3X_EQU_ENTRY_IDX_INVALID) ?
199 CTRL_BOARDOBJ_IDX_INVALID : (u8)equ.equ_idx_next;
200 equ_data.super.out_range_min = equ.out_range_min;
201 equ_data.super.out_range_max = equ.out_range_max;
202
203 switch (BIOS_GET_FIELD(equ.param3, VBIOS_VFE_3X_EQU_ENTRY_PAR3_OUTPUT_TYPE)) {
204 case VBIOS_VFE_3X_EQU_ENTRY_PAR3_OUTPUT_TYPE_UNITLESS:
205 equ_data.super.output_type =
206 CTRL_PERF_VFE_EQU_OUTPUT_TYPE_UNITLESS;
207 break;
208
209 case VBIOS_VFE_3X_EQU_ENTRY_PAR3_OUTPUT_TYPE_FREQ_MHZ:
210 equ_data.super.output_type =
211 CTRL_PERF_VFE_EQU_OUTPUT_TYPE_FREQ_MHZ;
212 break;
213
214 case VBIOS_VFE_3X_EQU_ENTRY_PAR3_OUTPUT_TYPE_VOLT_UV:
215 equ_data.super.output_type =
216 CTRL_PERF_VFE_EQU_OUTPUT_TYPE_VOLT_UV;
217 break;
218
219 case VBIOS_VFE_3X_EQU_ENTRY_PAR3_OUTPUT_TYPE_VF_GAIN:
220 equ_data.super.output_type =
221 CTRL_PERF_VFE_EQU_OUTPUT_TYPE_VF_GAIN;
222 break;
223
224 case VBIOS_VFE_3X_EQU_ENTRY_PAR3_OUTPUT_TYPE_VOLT_DELTA_UV:
225 equ_data.super.output_type =
226 CTRL_PERF_VFE_EQU_OUTPUT_TYPE_VOLT_DELTA_UV;
227 break;
228
229 default:
230 gk20a_err(dev_from_gk20a(g),
231 "unrecognized output id @vfeequ index %d",
232 index);
233 goto done;
234 }
235
236 switch ((u8)equ.type) {
237 case VBIOS_VFE_3X_EQU_ENTRY_TYPE_DISABLED:
238 case VBIOS_VFE_3X_EQU_ENTRY_TYPE_QUADRATIC_FXP:
239 case VBIOS_VFE_3X_EQU_ENTRY_TYPE_MINMAX_FXP:
240 continue;
241 break;
242
243 case VBIOS_VFE_3X_EQU_ENTRY_TYPE_QUADRATIC:
244 equ_type = CTRL_PERF_VFE_EQU_TYPE_QUADRATIC;
245 equ_data.quadratic.coeffs[0] = equ.param0;
246 equ_data.quadratic.coeffs[1] = equ.param1;
247 equ_data.quadratic.coeffs[2] = equ.param2;
248 break;
249
250 case VBIOS_VFE_3X_EQU_ENTRY_TYPE_MINMAX:
251 equ_type = CTRL_PERF_VFE_EQU_TYPE_MINMAX;
252 equ_data.minmax.b_max = BIOS_GET_FIELD(equ.param0,
253 VBIOS_VFE_3X_EQU_ENTRY_PAR0_MINMAX_CRIT) &&
254 VBIOS_VFE_3X_EQU_ENTRY_PAR0_MINMAX_CRIT_MAX;
255 equ_data.minmax.equ_idx0 = (u8)BIOS_GET_FIELD(
256 equ.param0,
257 VBIOS_VFE_3X_EQU_ENTRY_PAR0_MINMAX_VFE_EQU_IDX_0);
258 equ_data.minmax.equ_idx1 = (u8)BIOS_GET_FIELD(
259 equ.param0,
260 VBIOS_VFE_3X_EQU_ENTRY_PAR0_MINMAX_VFE_EQU_IDX_1);
261 break;
262
263 case VBIOS_VFE_3X_EQU_ENTRY_TYPE_COMPARE:
264 {
265 u8 cmp_func = (u8)BIOS_GET_FIELD(
266 equ.param1,
267 VBIOS_VFE_3X_EQU_ENTRY_PAR1_COMPARE_FUNCTION);
268 equ_type = CTRL_PERF_VFE_EQU_TYPE_COMPARE;
269
270 switch (cmp_func) {
271 case VBIOS_VFE_3X_EQU_ENTRY_PAR1_COMPARE_FUNCTION_EQUAL:
272 equ_data.compare.func_id =
273 CTRL_PERF_VFE_EQU_COMPARE_FUNCTION_EQUAL;
274 break;
275
276 case VBIOS_VFE_3X_EQU_ENTRY_PAR1_COMPARE_FUNCTION_GREATER_EQ:
277 equ_data.compare.func_id =
278 CTRL_PERF_VFE_EQU_COMPARE_FUNCTION_GREATER_EQ;
279 break;
280 case VBIOS_VFE_3X_EQU_ENTRY_PAR1_COMPARE_FUNCTION_GREATER:
281 equ_data.compare.func_id =
282 CTRL_PERF_VFE_EQU_COMPARE_FUNCTION_GREATER;
283 break;
284 default:
285 gk20a_err(dev_from_gk20a(g),
286 "invalid vfe compare index %x type %x ",
287 index, cmp_func);
288 status = -EINVAL;
289 goto done;
290 }
291 equ_data.compare.equ_idx_true = (u8)BIOS_GET_FIELD(
292 equ.param1,
293 VBIOS_VFE_3X_EQU_ENTRY_PAR1_COMPARE_VFE_EQU_IDX_TRUE);
294 equ_data.compare.equ_idx_false = (u8)BIOS_GET_FIELD(
295 equ.param1,
296 VBIOS_VFE_3X_EQU_ENTRY_PAR1_COMPARE_VFE_EQU_IDX_FALSE);
297 equ_data.compare.criteria = equ.param0;
298 break;
299 }
300 default:
301 status = -EINVAL;
302 gk20a_err(dev_from_gk20a(g),
303 "Invalid equ[%d].type = 0x%x.",
304 index, (u8)equ.type);
305 goto done;
306 }
307
308 equ_data.board_obj.type = equ_type;
309 pequ = construct_vfe_equ(g, (void *)&equ_data);
310
311 if (pequ == NULL) {
312 gk20a_err(dev_from_gk20a(g),
313 "error constructing vfe_equ boardobj %d", index);
314 status = -EINVAL;
315 goto done;
316 }
317
318 status = boardobjgrp_objinsert(&pvfeequobjs->super.super,
319 (struct boardobj *)pequ, index);
320 if (status) {
321 gk20a_err(dev_from_gk20a(g),
322 "error adding vfe_equ boardobj %d", index);
323 status = -EINVAL;
324 goto done;
325 }
326 }
327done:
328 gk20a_dbg_info(" done status %x", status);
329 return status;
330}
331
332static u32 _vfe_equ_pmudatainit_super(struct gk20a *g,
333 struct boardobj *board_obj_ptr,
334 struct nv_pmu_boardobj *ppmudata)
335{
336 u32 status = 0;
337 struct vfe_equ *pvfe_equ;
338 struct nv_pmu_vfe_equ *pset;
339
340 gk20a_dbg_info("");
341
342 status = boardobj_pmudatainit_super(g, board_obj_ptr, ppmudata);
343 if (status != 0)
344 return status;
345
346 pvfe_equ = (struct vfe_equ *)board_obj_ptr;
347
348 pset = (struct nv_pmu_vfe_equ *)
349 ppmudata;
350
351 pset->var_idx = pvfe_equ->var_idx;
352 pset->equ_idx_next = pvfe_equ->equ_idx_next;
353 pset->output_type = pvfe_equ->output_type;
354 pset->out_range_min = pvfe_equ->out_range_min;
355 pset->out_range_max = pvfe_equ->out_range_max;
356
357 return status;
358}
359
360static u32 vfe_equ_construct_super(struct gk20a *g,
361 struct boardobj **ppboardobj,
362 u16 size, void *pargs)
363{
364 struct vfe_equ *pvfeequ;
365 struct vfe_equ *ptmpequ = (struct vfe_equ *)pargs;
366 u32 status = 0;
367
368 status = boardobj_construct_super(g, ppboardobj,
369 size, pargs);
370 if (status)
371 return -EINVAL;
372
373 pvfeequ = (struct vfe_equ *)*ppboardobj;
374
375 pvfeequ->super.pmudatainit =
376 _vfe_equ_pmudatainit_super;
377
378 pvfeequ->var_idx = ptmpequ->var_idx;
379 pvfeequ->equ_idx_next = ptmpequ->equ_idx_next;
380 pvfeequ->output_type = ptmpequ->output_type;
381 pvfeequ->out_range_min = ptmpequ->out_range_min;
382 pvfeequ->out_range_max = ptmpequ->out_range_max;
383
384 return status;
385}
386
387static u32 _vfe_equ_pmudatainit_compare(struct gk20a *g,
388 struct boardobj *board_obj_ptr,
389 struct nv_pmu_boardobj *ppmudata)
390{
391 u32 status = 0;
392 struct vfe_equ_compare *pvfe_equ_compare;
393 struct nv_pmu_vfe_equ_compare *pset;
394
395 gk20a_dbg_info("");
396
397 status = _vfe_equ_pmudatainit_super(g, board_obj_ptr, ppmudata);
398 if (status != 0)
399 return status;
400
401 pvfe_equ_compare = (struct vfe_equ_compare *)board_obj_ptr;
402
403 pset = (struct nv_pmu_vfe_equ_compare *) ppmudata;
404
405 pset->func_id = pvfe_equ_compare->func_id;
406 pset->equ_idx_true = pvfe_equ_compare->equ_idx_true;
407 pset->equ_idx_false = pvfe_equ_compare->equ_idx_false;
408 pset->criteria = pvfe_equ_compare->criteria;
409
410 return status;
411}
412
413
414static u32 vfe_equ_construct_compare(struct gk20a *g,
415 struct boardobj **ppboardobj,
416 u16 size, void *pargs)
417{
418 struct boardobj *ptmpobj = (struct boardobj *)pargs;
419 struct vfe_equ_compare *pvfeequ;
420 struct vfe_equ_compare *ptmpequ =
421 (struct vfe_equ_compare *)pargs;
422 u32 status = 0;
423
424 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_PERF_VFE_EQU_TYPE_COMPARE)
425 return -EINVAL;
426
427 ptmpobj->type_mask |= BIT(CTRL_PERF_VFE_EQU_TYPE_COMPARE);
428 status = vfe_equ_construct_super(g, ppboardobj, size, pargs);
429 if (status)
430 return -EINVAL;
431
432 pvfeequ = (struct vfe_equ_compare *)*ppboardobj;
433
434 pvfeequ->super.super.pmudatainit =
435 _vfe_equ_pmudatainit_compare;
436
437 pvfeequ->func_id = ptmpequ->func_id;
438 pvfeequ->equ_idx_true = ptmpequ->equ_idx_true;
439 pvfeequ->equ_idx_false = ptmpequ->equ_idx_false;
440 pvfeequ->criteria = ptmpequ->criteria;
441
442
443 return status;
444}
445
446static u32 _vfe_equ_pmudatainit_minmax(struct gk20a *g,
447 struct boardobj *board_obj_ptr,
448 struct nv_pmu_boardobj *ppmudata)
449{
450 u32 status = 0;
451 struct vfe_equ_minmax *pvfe_equ_minmax;
452 struct nv_pmu_vfe_equ_minmax *pset;
453
454 gk20a_dbg_info("");
455
456 status = _vfe_equ_pmudatainit_super(g, board_obj_ptr, ppmudata);
457 if (status != 0)
458 return status;
459
460 pvfe_equ_minmax = (struct vfe_equ_minmax *)board_obj_ptr;
461
462 pset = (struct nv_pmu_vfe_equ_minmax *)
463 ppmudata;
464
465 pset->b_max = pvfe_equ_minmax->b_max;
466 pset->equ_idx0 = pvfe_equ_minmax->equ_idx0;
467 pset->equ_idx1 = pvfe_equ_minmax->equ_idx1;
468
469 return status;
470}
471
472static u32 vfe_equ_construct_minmax(struct gk20a *g,
473 struct boardobj **ppboardobj,
474 u16 size, void *pargs)
475{
476 struct boardobj *ptmpobj = (struct boardobj *)pargs;
477 struct vfe_equ_minmax *pvfeequ;
478 struct vfe_equ_minmax *ptmpequ =
479 (struct vfe_equ_minmax *)pargs;
480 u32 status = 0;
481
482 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_PERF_VFE_EQU_TYPE_MINMAX)
483 return -EINVAL;
484
485 ptmpobj->type_mask |= BIT(CTRL_PERF_VFE_EQU_TYPE_MINMAX);
486 status = vfe_equ_construct_super(g, ppboardobj, size, pargs);
487 if (status)
488 return -EINVAL;
489
490 pvfeequ = (struct vfe_equ_minmax *)*ppboardobj;
491
492 pvfeequ->super.super.pmudatainit =
493 _vfe_equ_pmudatainit_minmax;
494 pvfeequ->b_max = ptmpequ->b_max;
495 pvfeequ->equ_idx0 = ptmpequ->equ_idx0;
496 pvfeequ->equ_idx1 = ptmpequ->equ_idx1;
497
498 return status;
499}
500
501static u32 _vfe_equ_pmudatainit_quadratic(struct gk20a *g,
502 struct boardobj *board_obj_ptr,
503 struct nv_pmu_boardobj *ppmudata)
504{
505 u32 status = 0;
506 struct vfe_equ_quadratic *pvfe_equ_quadratic;
507 struct nv_pmu_vfe_equ_quadratic *pset;
508 u32 i;
509
510 gk20a_dbg_info("");
511
512 status = _vfe_equ_pmudatainit_super(g, board_obj_ptr, ppmudata);
513 if (status != 0)
514 return status;
515
516 pvfe_equ_quadratic = (struct vfe_equ_quadratic *)board_obj_ptr;
517
518 pset = (struct nv_pmu_vfe_equ_quadratic *) ppmudata;
519
520 for (i = 0; i < CTRL_PERF_VFE_EQU_QUADRATIC_COEFF_COUNT; i++)
521 pset->coeffs[i] = pvfe_equ_quadratic->coeffs[i];
522
523 return status;
524}
525
526static u32 vfe_equ_construct_quadratic(struct gk20a *g,
527 struct boardobj **ppboardobj,
528 u16 size, void *pargs)
529{
530 struct boardobj *ptmpobj = (struct boardobj *)pargs;
531 struct vfe_equ_quadratic *pvfeequ;
532 struct vfe_equ_quadratic *ptmpequ =
533 (struct vfe_equ_quadratic *)pargs;
534 u32 status = 0;
535 u32 i;
536
537 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_PERF_VFE_EQU_TYPE_QUADRATIC)
538 return -EINVAL;
539
540 ptmpobj->type_mask |= BIT(CTRL_PERF_VFE_EQU_TYPE_QUADRATIC);
541 status = vfe_equ_construct_super(g, ppboardobj, size, pargs);
542 if (status)
543 return -EINVAL;
544
545 pvfeequ = (struct vfe_equ_quadratic *)*ppboardobj;
546
547 pvfeequ->super.super.pmudatainit =
548 _vfe_equ_pmudatainit_quadratic;
549
550 for (i = 0; i < CTRL_PERF_VFE_EQU_QUADRATIC_COEFF_COUNT; i++)
551 pvfeequ->coeffs[i] = ptmpequ->coeffs[i];
552
553 return status;
554}
555
556static struct vfe_equ *construct_vfe_equ(struct gk20a *g, void *pargs)
557{
558 struct boardobj *board_obj_ptr = NULL;
559 u32 status;
560
561 gk20a_dbg_info("");
562
563 switch (BOARDOBJ_GET_TYPE(pargs)) {
564 case CTRL_PERF_VFE_EQU_TYPE_COMPARE:
565 status = vfe_equ_construct_compare(g, &board_obj_ptr,
566 sizeof(struct vfe_equ_compare), pargs);
567 break;
568
569 case CTRL_PERF_VFE_EQU_TYPE_MINMAX:
570 status = vfe_equ_construct_minmax(g, &board_obj_ptr,
571 sizeof(struct vfe_equ_minmax), pargs);
572 break;
573
574 case CTRL_PERF_VFE_EQU_TYPE_QUADRATIC:
575 status = vfe_equ_construct_quadratic(g, &board_obj_ptr,
576 sizeof(struct vfe_equ_quadratic), pargs);
577 break;
578
579 default:
580 return NULL;
581
582 }
583
584 if (status)
585 return NULL;
586
587 gk20a_dbg_info(" Done");
588
589 return (struct vfe_equ *)board_obj_ptr;
590}
diff --git a/drivers/gpu/nvgpu/perf/vfe_equ.h b/drivers/gpu/nvgpu/perf/vfe_equ.h
new file mode 100644
index 00000000..8aaddccd
--- /dev/null
+++ b/drivers/gpu/nvgpu/perf/vfe_equ.h
@@ -0,0 +1,76 @@
1/*
2 * general perf 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 _VFE_EQU_H_
16#define _VFE_EQU_H_
17
18#include "boardobj/boardobjgrp.h"
19#include "perf/vfe_var.h"
20#include "pmuif/gpmuifperf.h"
21#include "pmuif/gpmuifperfvfe.h"
22
23u32 vfe_equ_sw_setup(struct gk20a *g);
24u32 vfe_equ_pmu_setup(struct gk20a *g);
25
26#define VFE_EQU_GET(_pperf, _idx) \
27 ((struct vfe_equ *)BOARDOBJGRP_OBJ_GET_BY_IDX( \
28 &((_pperf)->vfe.equs.super.super), (_idx)))
29
30#define VFE_EQU_IDX_IS_VALID(_pperf, _idx) \
31 boardobjgrp_idxisvalid(&((_pperf)->vfe.equs.super.super), (_idx))
32
33#define VFE_EQU_OUTPUT_TYPE_IS_VALID(_pperf, _idx, _outputtype) \
34 (VFE_EQU_IDX_IS_VALID((_pperf), (_idx)) && \
35 ((_outputtype) != CTRL_PERF_VFE_EQU_OUTPUT_TYPE_UNITLESS) && \
36 ((VFE_EQU_GET((_pperf), (_idx))->outputtype == (_outputtype)) || \
37 (VFE_EQU_GET((_pperf), (_idx))->outputtype == \
38 CTRL_PERF_VFE_EQU_OUTPUT_TYPE_UNITLESS)))
39
40struct vfe_equ {
41 struct boardobj super;
42 u8 var_idx;
43 u8 equ_idx_next;
44 u8 output_type;
45 u32 out_range_min;
46 u32 out_range_max;
47
48 bool b_is_dynamic_valid;
49 bool b_is_dynamic;
50};
51
52struct vfe_equs {
53 struct boardobjgrp_e255 super;
54};
55
56struct vfe_equ_compare {
57 struct vfe_equ super;
58 u8 func_id;
59 u8 equ_idx_true;
60 u8 equ_idx_false;
61 u32 criteria;
62};
63
64struct vfe_equ_minmax {
65 struct vfe_equ super;
66 bool b_max;
67 u8 equ_idx0;
68 u8 equ_idx1;
69};
70
71struct vfe_equ_quadratic {
72 struct vfe_equ super;
73 u32 coeffs[CTRL_PERF_VFE_EQU_QUADRATIC_COEFF_COUNT];
74};
75
76#endif
diff --git a/drivers/gpu/nvgpu/perf/vfe_var.c b/drivers/gpu/nvgpu/perf/vfe_var.c
new file mode 100644
index 00000000..90963478
--- /dev/null
+++ b/drivers/gpu/nvgpu/perf/vfe_var.c
@@ -0,0 +1,1048 @@
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 "perf.h"
16#include "vfe_var.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/gpmuifperf.h"
22#include "pmuif/gpmuifperfvfe.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 u32 devinit_get_vfe_var_table(struct gk20a *g,
29 struct vfe_vars *pvarobjs);
30static u32 vfe_var_construct_single(struct gk20a *g,
31 struct boardobj **ppboardobj,
32 u16 size, void *pargs);
33
34static u32 _vfe_vars_pmudatainit(struct gk20a *g,
35 struct boardobjgrp *pboardobjgrp,
36 struct nv_pmu_boardobjgrp_super *pboardobjgrppmu)
37{
38 struct nv_pmu_perf_vfe_var_boardobjgrp_set_header *pset =
39 (struct nv_pmu_perf_vfe_var_boardobjgrp_set_header *)
40 pboardobjgrppmu;
41 struct vfe_vars *pvars = (struct vfe_vars *)pboardobjgrp;
42 u32 status = 0;
43
44 status = boardobjgrp_pmudatainit_e32(g, pboardobjgrp, pboardobjgrppmu);
45 if (status) {
46 gk20a_err(dev_from_gk20a(g),
47 "error updating pmu boardobjgrp for vfe var 0x%x",
48 status);
49 goto done;
50 }
51 pset->polling_periodms = pvars->polling_periodms;
52
53done:
54 return status;
55}
56
57static u32 _vfe_vars_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_perf_vfe_var_boardobj_grp_set *pgrp_set =
63 (struct nv_pmu_perf_vfe_var_boardobj_grp_set *)
64 pmuboardobjgrp;
65
66 gk20a_dbg_info("");
67
68 /*check whether pmuboardobjgrp has a valid boardobj in index*/
69 if (idx >= CTRL_BOARDOBJGRP_E32_MAX_OBJECTS)
70 return -EINVAL;
71
72 *ppboardobjpmudata = (struct nv_pmu_boardobj *)
73 &pgrp_set->objects[idx].data.board_obj;
74
75 gk20a_dbg_info(" Done");
76 return 0;
77}
78
79static u32 _vfe_vars_pmustatus_instget(struct gk20a *g, void *pboardobjgrppmu,
80 struct nv_pmu_boardobj_query **ppboardobjpmustatus, u8 idx)
81{
82 struct nv_pmu_perf_vfe_var_boardobj_grp_get_status *pgrp_get_status =
83 (struct nv_pmu_perf_vfe_var_boardobj_grp_get_status *)
84 pboardobjgrppmu;
85
86 if (((u32)BIT(idx) &
87 pgrp_get_status->hdr.data.super.obj_mask.super.data[0]) == 0)
88 return -EINVAL;
89
90 *ppboardobjpmustatus = (struct nv_pmu_boardobj_query *)
91 &pgrp_get_status->objects[idx].data.board_obj;
92 return 0;
93}
94
95
96u32 vfe_var_sw_setup(struct gk20a *g)
97{
98 u32 status;
99 struct boardobjgrp *pboardobjgrp = NULL;
100 struct vfe_vars *pvfevarobjs;
101
102 gk20a_dbg_info("");
103
104 status = boardobjgrpconstruct_e32(&g->perf_pmu.vfe_varobjs.super);
105 if (status) {
106 gk20a_err(dev_from_gk20a(g),
107 "error creating boardobjgrp for clk domain, status - 0x%x",
108 status);
109 goto done;
110 }
111
112 pboardobjgrp = &g->perf_pmu.vfe_varobjs.super.super;
113 pvfevarobjs = &g->perf_pmu.vfe_varobjs;
114
115 BOARDOBJGRP_PMU_CONSTRUCT(pboardobjgrp, PERF, VFE_VAR);
116
117 status = BOARDOBJGRP_PMU_CMD_GRP_SET_CONSTRUCT(g, pboardobjgrp,
118 perf, PERF, vfe_var, VFE_VAR);
119 if (status) {
120 gk20a_err(dev_from_gk20a(g),
121 "error constructing PMU_BOARDOBJ_CMD_GRP_SET interface - 0x%x",
122 status);
123 goto done;
124 }
125
126 pboardobjgrp->pmudatainit = _vfe_vars_pmudatainit;
127 pboardobjgrp->pmudatainstget = _vfe_vars_pmudata_instget;
128 pboardobjgrp->pmustatusinstget = _vfe_vars_pmustatus_instget;
129
130 status = devinit_get_vfe_var_table(g, pvfevarobjs);
131 if (status)
132 goto done;
133
134 status = BOARDOBJGRP_PMU_CMD_GRP_GET_STATUS_CONSTRUCT(g,
135 &g->perf_pmu.vfe_varobjs.super.super,
136 perf, PERF, vfe_var, VFE_VAR);
137 if (status) {
138 gk20a_err(dev_from_gk20a(g),
139 "error constructing PMU_BOARDOBJ_CMD_GRP_GET_STATUS interface - 0x%x",
140 status);
141 goto done;
142 }
143
144done:
145 gk20a_dbg_info(" done status %x", status);
146 return status;
147}
148
149u32 vfe_var_pmu_setup(struct gk20a *g)
150{
151 u32 status;
152 struct boardobjgrp *pboardobjgrp = NULL;
153
154 gk20a_dbg_info("");
155
156 pboardobjgrp = &g->perf_pmu.vfe_varobjs.super.super;
157
158 if (!pboardobjgrp->bconstructed)
159 return -EINVAL;
160
161 status = pboardobjgrp->pmuinithandle(g, pboardobjgrp);
162
163 gk20a_dbg_info("Done");
164 return status;
165}
166
167u32 dev_init_get_vfield_info(struct gk20a *g,
168 struct vfe_var_single_sensed_fuse *pvfevar)
169{
170 u8 *vfieldtableptr = NULL;
171 u32 vfieldheadersize = VFIELD_HEADER_SIZE;
172 u8 *vfieldregtableptr = NULL;
173 u32 vfieldregheadersize = VFIELD_REG_HEADER_SIZE;
174 u32 i;
175 u32 oldindex = 0xFFFFFFFF;
176 u32 currindex;
177 struct vfield_reg_header vregheader;
178 struct vfield_reg_entry vregentry;
179 struct vfield_header vheader;
180 struct vfield_entry ventry;
181 union nv_pmu_bios_vfield_register_segment *psegment = NULL;
182 u8 *psegmentcount = NULL;
183 u32 status = 0;
184
185 if (g->ops.bios.get_perf_table_ptrs) {
186 vfieldregtableptr = (u8 *)g->ops.bios.get_perf_table_ptrs(g,
187 g->bios.virt_token, VP_FIELD_REGISTER);
188 if (vfieldregtableptr == NULL) {
189 status = -EINVAL;
190 goto done;
191 }
192
193 vfieldtableptr = (u8 *)g->ops.bios.get_perf_table_ptrs(g,
194 g->bios.virt_token, VP_FIELD_TABLE);
195 if (vfieldtableptr == NULL) {
196 status = -EINVAL;
197 goto done;
198 }
199 }
200
201 memcpy(&vregheader, vfieldregtableptr, VFIELD_REG_HEADER_SIZE);
202
203 if (vregheader.version != VBIOS_VFIELD_REG_TABLE_VERSION_1_0) {
204 gk20a_err(dev_from_gk20a(g), "invalid vreg header version");
205 goto done;
206 }
207
208 memcpy(&vheader, vfieldtableptr, VFIELD_HEADER_SIZE);
209
210 if (vregheader.version != VBIOS_VFIELD_TABLE_VERSION_1_0) {
211 gk20a_err(dev_from_gk20a(g), "invalid vfield header version");
212 goto done;
213 }
214
215 pvfevar->vfield_info.fuse.segment_count = 0;
216 pvfevar->vfield_ver_info.fuse.segment_count = 0;
217 for (i = 0; i < (u32)vheader.count; i++) {
218 memcpy(&ventry, vfieldtableptr + vfieldheadersize +
219 (i * vheader.entry_size),
220 vheader.entry_size);
221
222 currindex = VFIELD_BIT_REG(ventry);
223 if (currindex != oldindex) {
224
225 memcpy(&vregentry, vfieldregtableptr +
226 vfieldregheadersize +
227 (currindex * vregheader.entry_size),
228 vregheader.entry_size);
229 oldindex = currindex;
230 }
231
232 if (pvfevar->vfield_info.v_field_id == ventry.strap_id) {
233 psegmentcount =
234 &(pvfevar->vfield_info.fuse.segment_count);
235 psegment =
236 &(pvfevar->vfield_info.fuse.segments[*psegmentcount]);
237 if (*psegmentcount > NV_PMU_VFE_VAR_SINGLE_SENSED_FUSE_SEGMENTS_MAX) {
238 status = -EINVAL;
239 goto done;
240 }
241 } else if (pvfevar->vfield_ver_info.v_field_id_ver == ventry.strap_id) {
242 psegmentcount =
243 &(pvfevar->vfield_ver_info.fuse.segment_count);
244 psegment =
245 &(pvfevar->vfield_ver_info.fuse.segments[*psegmentcount]);
246 if (*psegmentcount > NV_PMU_VFE_VAR_SINGLE_SENSED_FUSE_SEGMENTS_MAX) {
247 status = -EINVAL;
248 goto done;
249 }
250 } else {
251 continue;
252 }
253
254 psegment->super.high_bit = (u8)(VFIELD_BIT_STOP(ventry));
255 psegment->super.low_bit = (u8)(VFIELD_BIT_START(ventry));
256 switch (VFIELD_CODE((&vregentry))) {
257 case NV_VFIELD_DESC_CODE_REG:
258 psegment->reg.super.type =
259 NV_PMU_BIOS_VFIELD_DESC_CODE_REG;
260 psegment->reg.addr = vregentry.reg;
261 break;
262
263 case NV_VFIELD_DESC_CODE_INDEX_REG:
264 psegment->index_reg.super.type =
265 NV_PMU_BIOS_VFIELD_DESC_CODE_INDEX_REG;
266 psegment->index_reg.addr = vregentry.reg;
267 psegment->index_reg.index = vregentry.index;
268 psegment->index_reg.reg_index = vregentry.reg_index;
269 break;
270
271 default:
272 psegment->super.type =
273 NV_PMU_BIOS_VFIELD_DESC_CODE_INVALID;
274 status = -EINVAL;
275 goto done;
276 }
277
278 if (VFIELD_SIZE((&vregentry)) != NV_VFIELD_DESC_SIZE_DWORD) {
279 psegment->super.type =
280 NV_PMU_BIOS_VFIELD_DESC_CODE_INVALID;
281 return -EINVAL;
282 }
283 (*psegmentcount)++;
284 }
285
286done:
287
288 return status;
289}
290
291static u32 _vfe_var_pmudatainit_super(struct gk20a *g,
292 struct boardobj *board_obj_ptr,
293 struct nv_pmu_boardobj *ppmudata)
294{
295 u32 status = 0;
296 struct vfe_var *pvfe_var;
297 struct nv_pmu_vfe_var *pset;
298
299 gk20a_dbg_info("");
300
301 status = boardobj_pmudatainit_super(g, board_obj_ptr, ppmudata);
302 if (status != 0)
303 return status;
304
305 pvfe_var = (struct vfe_var *)board_obj_ptr;
306 pset = (struct nv_pmu_vfe_var *) ppmudata;
307
308 pset->out_range_min = pvfe_var->out_range_min;
309 pset->out_range_max = pvfe_var->out_range_max;
310
311 return status;
312}
313
314static u32 vfe_var_construct_super(struct gk20a *g,
315 struct boardobj **ppboardobj,
316 u16 size, void *pargs)
317{
318 struct vfe_var *pvfevar;
319 struct vfe_var *ptmpvar = (struct vfe_var *)pargs;
320 u32 status = 0;
321
322 gk20a_dbg_info("");
323
324 status = boardobj_construct_super(g, ppboardobj, size, pargs);
325 if (status)
326 return -EINVAL;
327
328 pvfevar = (struct vfe_var *)*ppboardobj;
329
330 pvfevar->super.pmudatainit =
331 _vfe_var_pmudatainit_super;
332
333 pvfevar->out_range_min = ptmpvar->out_range_min;
334 pvfevar->out_range_max = ptmpvar->out_range_max;
335 pvfevar->b_is_dynamic_valid = false;
336
337 gk20a_dbg_info("");
338
339 return status;
340}
341
342static u32 _vfe_var_pmudatainit_derived(struct gk20a *g,
343 struct boardobj *board_obj_ptr,
344 struct nv_pmu_boardobj *ppmudata)
345{
346 u32 status = 0;
347
348 gk20a_dbg_info("");
349
350 status = _vfe_var_pmudatainit_super(g, board_obj_ptr, ppmudata);
351
352 return status;
353}
354
355static u32 vfe_var_construct_derived(struct gk20a *g,
356 struct boardobj **ppboardobj,
357 u16 size, void *pargs)
358{
359 struct boardobj *ptmpobj = (struct boardobj *)pargs;
360 u32 status = 0;
361 struct vfe_var_derived *pvfevar;
362
363 ptmpobj->type_mask |= BIT(CTRL_PERF_VFE_VAR_TYPE_DERIVED);
364 status = vfe_var_construct_super(g, ppboardobj, size, pargs);
365 if (status)
366 return -EINVAL;
367
368 pvfevar = (struct vfe_var_derived *)*ppboardobj;
369
370 pvfevar->super.super.pmudatainit =
371 _vfe_var_pmudatainit_derived;
372
373 return status;
374}
375
376static u32 _vfe_var_pmudatainit_derived_product(struct gk20a *g,
377 struct boardobj *board_obj_ptr,
378 struct nv_pmu_boardobj *ppmudata)
379{
380 u32 status = 0;
381 struct vfe_var_derived_product *pvfe_var_derived_product;
382 struct nv_pmu_vfe_var_derived_product *pset;
383
384 gk20a_dbg_info("");
385
386 status = _vfe_var_pmudatainit_derived(g, board_obj_ptr, ppmudata);
387 if (status != 0)
388 return status;
389
390 pvfe_var_derived_product =
391 (struct vfe_var_derived_product *)board_obj_ptr;
392 pset = (struct nv_pmu_vfe_var_derived_product *)ppmudata;
393
394 pset->var_idx0 = pvfe_var_derived_product->var_idx0;
395 pset->var_idx1 = pvfe_var_derived_product->var_idx1;
396
397 return status;
398}
399
400static u32 vfe_var_construct_derived_product(struct gk20a *g,
401 struct boardobj **ppboardobj,
402 u16 size, void *pargs)
403{
404 struct boardobj *ptmpobj = (struct boardobj *)pargs;
405 struct vfe_var_derived_product *pvfevar;
406 struct vfe_var_derived_product *ptmpvar =
407 (struct vfe_var_derived_product *)pargs;
408 u32 status = 0;
409
410 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_PERF_VFE_VAR_TYPE_DERIVED_PRODUCT)
411 return -EINVAL;
412
413 ptmpobj->type_mask |= BIT(CTRL_PERF_VFE_VAR_TYPE_DERIVED_PRODUCT);
414 status = vfe_var_construct_derived(g, ppboardobj, size, pargs);
415 if (status)
416 return -EINVAL;
417
418 pvfevar = (struct vfe_var_derived_product *)*ppboardobj;
419
420 pvfevar->super.super.super.pmudatainit =
421 _vfe_var_pmudatainit_derived_product;
422
423 pvfevar->var_idx0 = ptmpvar->var_idx0;
424 pvfevar->var_idx1 = ptmpvar->var_idx1;
425
426
427 return status;
428}
429
430static u32 _vfe_var_pmudatainit_derived_sum(struct gk20a *g,
431 struct boardobj *board_obj_ptr,
432 struct nv_pmu_boardobj *ppmudata)
433{
434 u32 status = 0;
435 struct vfe_var_derived_sum *pvfe_var_derived_sum;
436 struct nv_pmu_vfe_var_derived_sum *pset;
437
438 gk20a_dbg_info("");
439
440 status = _vfe_var_pmudatainit_derived(g, board_obj_ptr, ppmudata);
441 if (status != 0)
442 return status;
443
444 pvfe_var_derived_sum = (struct vfe_var_derived_sum *)board_obj_ptr;
445 pset = (struct nv_pmu_vfe_var_derived_sum *)ppmudata;
446
447 pset->var_idx0 = pvfe_var_derived_sum->var_idx0;
448 pset->var_idx1 = pvfe_var_derived_sum->var_idx1;
449
450 return status;
451}
452
453static u32 vfe_var_construct_derived_sum(struct gk20a *g,
454 struct boardobj **ppboardobj,
455 u16 size, void *pargs)
456{
457 struct boardobj *ptmpobj = (struct boardobj *)pargs;
458 struct vfe_var_derived_sum *pvfevar;
459 struct vfe_var_derived_sum *ptmpvar =
460 (struct vfe_var_derived_sum *)pargs;
461 u32 status = 0;
462
463 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_PERF_VFE_VAR_TYPE_DERIVED_SUM)
464 return -EINVAL;
465
466 ptmpobj->type_mask |= BIT(CTRL_PERF_VFE_VAR_TYPE_DERIVED_SUM);
467 status = vfe_var_construct_derived(g, ppboardobj, size, pargs);
468 if (status)
469 return -EINVAL;
470
471 pvfevar = (struct vfe_var_derived_sum *)*ppboardobj;
472
473 pvfevar->super.super.super.pmudatainit =
474 _vfe_var_pmudatainit_derived_sum;
475
476 pvfevar->var_idx0 = ptmpvar->var_idx0;
477 pvfevar->var_idx1 = ptmpvar->var_idx1;
478
479 return status;
480}
481
482static u32 _vfe_var_pmudatainit_single(struct gk20a *g,
483 struct boardobj *board_obj_ptr,
484 struct nv_pmu_boardobj *ppmudata)
485{
486 u32 status = 0;
487 struct vfe_var_single *pvfe_var_single;
488 struct nv_pmu_vfe_var_single *pset;
489
490 gk20a_dbg_info("");
491
492 status = _vfe_var_pmudatainit_super(g, board_obj_ptr, ppmudata);
493 if (status != 0)
494 return status;
495
496 pvfe_var_single = (struct vfe_var_single *)board_obj_ptr;
497 pset = (struct nv_pmu_vfe_var_single *)
498 ppmudata;
499
500 pset->override_type = pvfe_var_single->override_type;
501 pset->override_value = pvfe_var_single->override_value;
502
503 return status;
504}
505
506static u32 _vfe_var_pmudatainit_single_frequency(struct gk20a *g,
507 struct boardobj *board_obj_ptr,
508 struct nv_pmu_boardobj *ppmudata)
509{
510 u32 status = 0;
511
512 gk20a_dbg_info("");
513
514 status = _vfe_var_pmudatainit_single(g, board_obj_ptr, ppmudata);
515
516 return status;
517}
518
519static u32 vfe_var_construct_single_frequency(struct gk20a *g,
520 struct boardobj **ppboardobj,
521 u16 size, void *pargs)
522{
523 struct boardobj *ptmpobj = (struct boardobj *)pargs;
524 struct vfe_var_single_frequency *pvfevar;
525 u32 status = 0;
526
527 gk20a_dbg_info("");
528
529 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_PERF_VFE_VAR_TYPE_SINGLE_FREQUENCY)
530 return -EINVAL;
531
532 ptmpobj->type_mask |= BIT(CTRL_PERF_VFE_VAR_TYPE_SINGLE_FREQUENCY);
533 status = vfe_var_construct_single(g, ppboardobj, size, pargs);
534 if (status)
535 return -EINVAL;
536
537 pvfevar = (struct vfe_var_single_frequency *)*ppboardobj;
538
539 pvfevar->super.super.super.pmudatainit =
540 _vfe_var_pmudatainit_single_frequency;
541
542 pvfevar->super.super.b_is_dynamic = false;
543 pvfevar->super.super.b_is_dynamic_valid = true;
544
545 gk20a_dbg_info("Done");
546 return status;
547}
548
549static u32 _vfe_var_pmudatainit_single_sensed(struct gk20a *g,
550 struct boardobj *board_obj_ptr,
551 struct nv_pmu_boardobj *ppmudata)
552{
553 u32 status = 0;
554
555 gk20a_dbg_info("");
556
557 status = _vfe_var_pmudatainit_single(g, board_obj_ptr, ppmudata);
558
559 return status;
560}
561
562static u32 _vfe_var_pmudatainit_single_sensed_fuse(struct gk20a *g,
563 struct boardobj *board_obj_ptr,
564 struct nv_pmu_boardobj *ppmudata)
565{
566 u32 status = 0;
567 struct vfe_var_single_sensed_fuse *pvfe_var_single_sensed_fuse;
568 struct nv_pmu_vfe_var_single_sensed_fuse *pset;
569
570 gk20a_dbg_info("");
571
572 status = _vfe_var_pmudatainit_single_sensed(g, board_obj_ptr, ppmudata);
573 if (status != 0)
574 return status;
575
576 pvfe_var_single_sensed_fuse =
577 (struct vfe_var_single_sensed_fuse *)board_obj_ptr;
578
579 pset = (struct nv_pmu_vfe_var_single_sensed_fuse *)
580 ppmudata;
581
582 memcpy(&pset->vfield_info, &pvfe_var_single_sensed_fuse->vfield_info,
583 sizeof(struct nv_pmu_vfe_var_single_sensed_fuse_vfield_info));
584
585 memcpy(&pset->vfield_ver_info,
586 &pvfe_var_single_sensed_fuse->vfield_ver_info,
587 sizeof(struct nv_pmu_vfe_var_single_sensed_fuse_ver_vfield_info));
588
589 memcpy(&pset->override_info,
590 &pvfe_var_single_sensed_fuse->override_info,
591 sizeof(struct nv_pmu_vfe_var_single_sensed_fuse_override_info));
592
593 return status;
594}
595
596static u32 vfe_var_construct_single_sensed(struct gk20a *g,
597 struct boardobj **ppboardobj,
598 u16 size, void *pargs)
599{
600 struct boardobj *ptmpobj = (struct boardobj *)pargs;
601 struct vfe_var_single_sensed *pvfevar;
602
603 u32 status = 0;
604
605 gk20a_dbg_info(" ");
606
607 ptmpobj->type_mask |= BIT(CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED);
608 status = vfe_var_construct_single(g, ppboardobj, size, pargs);
609 if (status)
610 return -EINVAL;
611
612 pvfevar = (struct vfe_var_single_sensed *)*ppboardobj;
613
614 pvfevar->super.super.super.pmudatainit =
615 _vfe_var_pmudatainit_single_sensed;
616
617 gk20a_dbg_info("Done");
618
619 return status;
620}
621
622static u32 vfe_var_construct_single_sensed_fuse(struct gk20a *g,
623 struct boardobj **ppboardobj,
624 u16 size, void *pargs)
625{
626 struct boardobj *ptmpobj = (struct boardobj *)pargs;
627 struct vfe_var_single_sensed_fuse *pvfevar;
628 struct vfe_var_single_sensed_fuse *ptmpvar =
629 (struct vfe_var_single_sensed_fuse *)pargs;
630 u32 status = 0;
631
632 gk20a_dbg_info("");
633
634 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED_FUSE)
635 return -EINVAL;
636
637 ptmpobj->type_mask |= BIT(CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED_FUSE);
638 status = vfe_var_construct_single_sensed(g, ppboardobj, size, pargs);
639 if (status)
640 return -EINVAL;
641
642 pvfevar = (struct vfe_var_single_sensed_fuse *)*ppboardobj;
643
644 pvfevar->super.super.super.super.pmudatainit =
645 _vfe_var_pmudatainit_single_sensed_fuse;
646
647 pvfevar->vfield_info.v_field_id = ptmpvar->vfield_info.v_field_id;
648 pvfevar->vfield_info.fuse_val_default =
649 ptmpvar->vfield_info.fuse_val_default;
650 pvfevar->vfield_info.hw_correction_scale =
651 ptmpvar->vfield_info.hw_correction_scale;
652 pvfevar->vfield_info.hw_correction_offset =
653 ptmpvar->vfield_info.hw_correction_offset;
654 pvfevar->vfield_ver_info.v_field_id_ver =
655 ptmpvar->vfield_ver_info.v_field_id_ver;
656 pvfevar->vfield_ver_info.ver_expected =
657 ptmpvar->vfield_ver_info.ver_expected;
658 pvfevar->vfield_ver_info.b_use_default_on_ver_check_fail =
659 ptmpvar->vfield_ver_info.b_use_default_on_ver_check_fail;
660 pvfevar->b_version_check_done = false;
661
662 pvfevar->super.super.super.b_is_dynamic = false;
663 pvfevar->super.super.super.b_is_dynamic_valid = true;
664
665 dev_init_get_vfield_info(g, pvfevar);
666 /*check whether fuse segment got initialized*/
667 if (pvfevar->vfield_info.fuse.segment_count == 0) {
668 gk20a_err(dev_from_gk20a(g), "unable to get fuse reg info %x",
669 pvfevar->vfield_info.v_field_id);
670 return -EINVAL;
671 }
672 if (pvfevar->vfield_ver_info.fuse.segment_count == 0) {
673 gk20a_err(dev_from_gk20a(g), "unable to get fuse reg info %x",
674 pvfevar->vfield_ver_info.v_field_id_ver);
675 return -EINVAL;
676 }
677 return status;
678}
679
680static u32 _vfe_var_pmudatainit_single_sensed_temp(struct gk20a *g,
681 struct boardobj *board_obj_ptr,
682 struct nv_pmu_boardobj *ppmudata)
683{
684 u32 status = 0;
685 struct vfe_var_single_sensed_temp *pvfe_var_single_sensed_temp;
686 struct nv_pmu_vfe_var_single_sensed_temp *pset;
687
688 gk20a_dbg_info("");
689
690 status = _vfe_var_pmudatainit_single_sensed(g, board_obj_ptr, ppmudata);
691 if (status != 0)
692 return status;
693
694 pvfe_var_single_sensed_temp =
695 (struct vfe_var_single_sensed_temp *)board_obj_ptr;
696
697 pset = (struct nv_pmu_vfe_var_single_sensed_temp *)
698 ppmudata;
699 pset->therm_channel_index =
700 pvfe_var_single_sensed_temp->therm_channel_index;
701 pset->temp_hysteresis_positive =
702 pvfe_var_single_sensed_temp->temp_hysteresis_positive;
703 pset->temp_hysteresis_negative =
704 pvfe_var_single_sensed_temp->temp_hysteresis_negative;
705 pset->temp_default =
706 pvfe_var_single_sensed_temp->temp_default;
707 return status;
708}
709
710static u32 vfe_var_construct_single_sensed_temp(struct gk20a *g,
711 struct boardobj **ppboardobj,
712 u16 size, void *pargs)
713{
714 struct boardobj *ptmpobj = (struct boardobj *)pargs;
715 struct vfe_var_single_sensed_temp *pvfevar;
716 struct vfe_var_single_sensed_temp *ptmpvar =
717 (struct vfe_var_single_sensed_temp *)pargs;
718 u32 status = 0;
719
720 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED_TEMP)
721 return -EINVAL;
722
723 ptmpobj->type_mask |= BIT(CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED_TEMP);
724 status = vfe_var_construct_single_sensed(g, ppboardobj, size, pargs);
725 if (status)
726 return -EINVAL;
727
728 pvfevar = (struct vfe_var_single_sensed_temp *)*ppboardobj;
729
730 pvfevar->super.super.super.super.pmudatainit =
731 _vfe_var_pmudatainit_single_sensed_temp;
732
733 pvfevar->therm_channel_index =
734 ptmpvar->therm_channel_index;
735 pvfevar->temp_hysteresis_positive =
736 ptmpvar->temp_hysteresis_positive;
737 pvfevar->temp_hysteresis_negative =
738 ptmpvar->temp_hysteresis_negative;
739 pvfevar->temp_default =
740 ptmpvar->temp_default;
741 pvfevar->super.super.super.b_is_dynamic = false;
742 pvfevar->super.super.super.b_is_dynamic_valid = true;
743
744 return status;
745}
746
747static u32 _vfe_var_pmudatainit_single_voltage(struct gk20a *g,
748 struct boardobj *board_obj_ptr,
749 struct nv_pmu_boardobj *ppmudata)
750{
751 u32 status = 0;
752
753 gk20a_dbg_info("");
754
755 status = _vfe_var_pmudatainit_single(g, board_obj_ptr, ppmudata);
756
757 return status;
758}
759
760static u32 vfe_var_construct_single_voltage(struct gk20a *g,
761 struct boardobj **ppboardobj,
762 u16 size, void *pargs)
763{
764 struct boardobj *ptmpobj = (struct boardobj *)pargs;
765 struct vfe_var_single_voltage *pvfevar;
766 u32 status = 0;
767
768 if (BOARDOBJ_GET_TYPE(pargs) != CTRL_PERF_VFE_VAR_TYPE_SINGLE_VOLTAGE)
769 return -EINVAL;
770
771 ptmpobj->type_mask |= BIT(CTRL_PERF_VFE_VAR_TYPE_SINGLE_VOLTAGE);
772 status = vfe_var_construct_super(g, ppboardobj, size, pargs);
773 if (status)
774 return -EINVAL;
775
776 pvfevar = (struct vfe_var_single_voltage *)*ppboardobj;
777
778 pvfevar->super.super.super.pmudatainit =
779 _vfe_var_pmudatainit_single_voltage;
780
781 pvfevar->super.super.b_is_dynamic = false;
782 pvfevar->super.super.b_is_dynamic_valid = true;
783
784 return status;
785}
786
787static struct vfe_var *construct_vfe_var(struct gk20a *g, void *pargs)
788{
789 struct boardobj *board_obj_ptr = NULL;
790 u32 status;
791
792 gk20a_dbg_info("");
793 switch (BOARDOBJ_GET_TYPE(pargs)) {
794 case CTRL_PERF_VFE_VAR_TYPE_DERIVED_PRODUCT:
795 status = vfe_var_construct_derived_product(g, &board_obj_ptr,
796 sizeof(struct vfe_var_derived_product), pargs);
797 break;
798
799 case CTRL_PERF_VFE_VAR_TYPE_DERIVED_SUM:
800 status = vfe_var_construct_derived_sum(g, &board_obj_ptr,
801 sizeof(struct vfe_var_derived_sum), pargs);
802 break;
803
804 case CTRL_PERF_VFE_VAR_TYPE_SINGLE_FREQUENCY:
805 status = vfe_var_construct_single_frequency(g, &board_obj_ptr,
806 sizeof(struct vfe_var_single_frequency), pargs);
807 break;
808
809 case CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED_FUSE:
810 status = vfe_var_construct_single_sensed_fuse(g, &board_obj_ptr,
811 sizeof(struct vfe_var_single_sensed_fuse), pargs);
812 break;
813
814 case CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED_TEMP:
815 status = vfe_var_construct_single_sensed_temp(g, &board_obj_ptr,
816 sizeof(struct vfe_var_single_sensed_temp), pargs);
817 break;
818
819 case CTRL_PERF_VFE_VAR_TYPE_SINGLE_VOLTAGE:
820 status = vfe_var_construct_single_voltage(g, &board_obj_ptr,
821 sizeof(struct vfe_var_single_voltage), pargs);
822 break;
823
824 case CTRL_PERF_VFE_VAR_TYPE_DERIVED:
825 case CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED:
826 case CTRL_PERF_VFE_VAR_TYPE_SINGLE:
827 default:
828 return NULL;
829 }
830
831 if (status)
832 return NULL;
833
834 gk20a_dbg_info("done");
835
836 return (struct vfe_var *)board_obj_ptr;
837}
838
839static u32 devinit_get_vfe_var_table(struct gk20a *g,
840 struct vfe_vars *pvfevarobjs)
841{
842 u32 status = 0;
843 u8 *vfevars_tbl_ptr = NULL;
844 struct vbios_vfe_3x_header_struct vfevars_tbl_header = { 0 };
845 struct vbios_vfe_3x_var_entry_struct var = { 0 };
846 u8 *vfevars_tbl_entry_ptr = NULL;
847 u8 *rd_offset_ptr = NULL;
848 u32 index = 0;
849 struct vfe_var *pvar;
850 u8 var_type;
851 u32 szfmt;
852 union {
853 struct boardobj board_obj;
854 struct vfe_var super;
855 struct vfe_var_derived_product derived_product;
856 struct vfe_var_derived_sum derived_sum;
857 struct vfe_var_single_sensed_fuse single_sensed_fuse;
858 struct vfe_var_single_sensed_temp single_sensed_temp;
859 } var_data;
860
861 gk20a_dbg_info("");
862
863 if (g->ops.bios.get_perf_table_ptrs) {
864 vfevars_tbl_ptr = (u8 *)g->ops.bios.get_perf_table_ptrs(g,
865 g->bios.perf_token,
866 CONTINUOUS_VIRTUAL_BINNING_TABLE);
867 if (vfevars_tbl_ptr == NULL) {
868 status = -EINVAL;
869 goto done;
870 }
871 }
872
873 memcpy(&vfevars_tbl_header, vfevars_tbl_ptr,
874 VBIOS_CLOCKS_TABLE_1X_HEADER_SIZE_07);
875 if (vfevars_tbl_header.header_size !=
876 VBIOS_CLOCKS_TABLE_1X_HEADER_SIZE_07){
877 status = -EINVAL;
878 goto done;
879 }
880
881 if (vfevars_tbl_header.vfe_var_entry_size ==
882 VBIOS_VFE_3X_VAR_ENTRY_SIZE_19)
883 szfmt = VBIOS_VFE_3X_VAR_ENTRY_SIZE_19;
884 else if (vfevars_tbl_header.vfe_var_entry_size ==
885 VBIOS_VFE_3X_VAR_ENTRY_SIZE_11)
886 szfmt = VBIOS_VFE_3X_VAR_ENTRY_SIZE_11;
887 else {
888 status = -EINVAL;
889 goto done;
890 }
891
892 /* Read table entries*/
893 vfevars_tbl_entry_ptr = vfevars_tbl_ptr +
894 vfevars_tbl_header.header_size;
895
896 for (index = 0;
897 index < vfevars_tbl_header.vfe_var_entry_count;
898 index++) {
899 rd_offset_ptr = vfevars_tbl_entry_ptr +
900 (index * vfevars_tbl_header.vfe_var_entry_size);
901 memcpy(&var, rd_offset_ptr, szfmt);
902
903 var_data.super.out_range_min = var.out_range_min;
904 var_data.super.out_range_max = var.out_range_max;
905
906 var_data.super.out_range_min = var.out_range_min;
907 var_data.super.out_range_max = var.out_range_max;
908
909 switch ((u8)var.type) {
910 case VBIOS_VFE_3X_VAR_ENTRY_TYPE_DISABLED:
911 continue;
912 break;
913
914 case VBIOS_VFE_3X_VAR_ENTRY_TYPE_SINGLE_FREQUENCY:
915 var_type = CTRL_PERF_VFE_VAR_TYPE_SINGLE_FREQUENCY;
916 break;
917
918 case VBIOS_VFE_3X_VAR_ENTRY_TYPE_SINGLE_VOLTAGE:
919 var_type = CTRL_PERF_VFE_VAR_TYPE_SINGLE_VOLTAGE;
920 break;
921
922 case VBIOS_VFE_3X_VAR_ENTRY_TYPE_SINGLE_SENSED_TEMP:
923 var_type = CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED_TEMP;
924 var_data.single_sensed_temp.temp_default = 105;
925 var_data.single_sensed_temp.therm_channel_index =
926 (u8)BIOS_GET_FIELD(var.param0,
927 VBIOS_VFE_3X_VAR_ENTRY_PAR0_SSTEMP_TH_CH_IDX);
928 var_data.single_sensed_temp.temp_hysteresis_positive =
929 (u8)BIOS_GET_FIELD(var.param0,
930 VBIOS_VFE_3X_VAR_ENTRY_PAR0_SSTEMP_HYS_POS) << 5;
931 var_data.single_sensed_temp.temp_hysteresis_negative =
932 (u8)BIOS_GET_FIELD(var.param0,
933 VBIOS_VFE_3X_VAR_ENTRY_PAR0_SSTEMP_HYS_NEG) << 5;
934 break;
935
936 case VBIOS_VFE_3X_VAR_ENTRY_TYPE_SINGLE_SENSED_FUSE:
937 var_type = CTRL_PERF_VFE_VAR_TYPE_SINGLE_SENSED_FUSE;
938 var_data.single_sensed_fuse.vfield_info.v_field_id =
939 (u8)BIOS_GET_FIELD(var.param0,
940 VBIOS_VFE_3X_VAR_ENTRY_PAR0_SSFUSE_VFIELD_ID);
941 var_data.single_sensed_fuse.vfield_ver_info.v_field_id_ver =
942 (u8)BIOS_GET_FIELD(var.param0,
943 VBIOS_VFE_3X_VAR_ENTRY_PAR0_SSFUSE_VFIELD_ID_VER);
944 var_data.single_sensed_fuse.vfield_ver_info.ver_expected =
945 (u8)BIOS_GET_FIELD(var.param0,
946 VBIOS_VFE_3X_VAR_ENTRY_PAR0_SSFUSE_EXPECTED_VER);
947 var_data.single_sensed_fuse.vfield_ver_info.b_use_default_on_ver_check_fail =
948 (BIOS_GET_FIELD(var.param0,
949 VBIOS_VFE_3X_VAR_ENTRY_PAR0_SSFUSE_USE_DEFAULT_ON_VER_CHECK_FAIL) &&
950 VBIOS_VFE_3X_VAR_ENTRY_PAR0_SSFUSE_USE_DEFAULT_ON_VER_CHECK_FAIL_YES);
951 var_data.single_sensed_fuse.vfield_info.fuse_val_default =
952 var.param1;
953 if (szfmt >= VBIOS_VFE_3X_VAR_ENTRY_SIZE_19) {
954 var_data.single_sensed_fuse.vfield_info.hw_correction_scale =
955 (int)var.param2;
956 var_data.single_sensed_fuse.vfield_info.hw_correction_offset =
957 var.param3;
958 } else {
959 var_data.single_sensed_fuse.vfield_info.hw_correction_scale =
960 1 << 12;
961 var_data.single_sensed_fuse.vfield_info.hw_correction_offset =
962 0;
963 if ((var_data.single_sensed_fuse.vfield_info.v_field_id ==
964 VFIELD_ID_STRAP_IDDQ) ||
965 (var_data.single_sensed_fuse.vfield_info.v_field_id ==
966 VFIELD_ID_STRAP_IDDQ_1)) {
967 var_data.single_sensed_fuse.vfield_info.hw_correction_scale =
968 50 << 12;
969 }
970 }
971 break;
972
973 case VBIOS_VFE_3X_VAR_ENTRY_TYPE_DERIVED_PRODUCT:
974 var_type = CTRL_PERF_VFE_VAR_TYPE_DERIVED_PRODUCT;
975 var_data.derived_product.var_idx0 =
976 (u8)BIOS_GET_FIELD(var.param0,
977 VBIOS_VFE_3X_VAR_ENTRY_PAR0_DPROD_VFE_VAR_IDX_0);
978 var_data.derived_product.var_idx1 =
979 (u8)BIOS_GET_FIELD(var.param0,
980 VBIOS_VFE_3X_VAR_ENTRY_PAR0_DPROD_VFE_VAR_IDX_1);
981 break;
982
983 case VBIOS_VFE_3X_VAR_ENTRY_TYPE_DERIVED_SUM:
984 var_type = CTRL_PERF_VFE_VAR_TYPE_DERIVED_SUM;
985 var_data.derived_sum.var_idx0 =
986 (u8)BIOS_GET_FIELD(var.param0,
987 VBIOS_VFE_3X_VAR_ENTRY_PAR0_DSUM_VFE_VAR_IDX_0);
988 var_data.derived_sum.var_idx1 =
989 (u8)BIOS_GET_FIELD(var.param0,
990 VBIOS_VFE_3X_VAR_ENTRY_PAR0_DSUM_VFE_VAR_IDX_1);
991 break;
992 default:
993 status = -EINVAL;
994 goto done;
995 }
996 var_data.board_obj.type = var_type;
997 var_data.board_obj.type_mask = 0;
998
999 pvar = construct_vfe_var(g, &var_data);
1000 if (pvar == NULL) {
1001 gk20a_err(dev_from_gk20a(g),
1002 "error constructing vfe_var boardobj %d",
1003 index);
1004 status = -EINVAL;
1005 goto done;
1006 }
1007
1008 status = boardobjgrp_objinsert(&pvfevarobjs->super.super,
1009 (struct boardobj *)pvar, index);
1010 if (status) {
1011 gk20a_err(dev_from_gk20a(g),
1012 "error adding vfe_var boardobj %d", index);
1013 status = -EINVAL;
1014 goto done;
1015 }
1016 }
1017 pvfevarobjs->polling_periodms = vfevars_tbl_header.polling_periodms;
1018done:
1019 gk20a_dbg_info("done status %x", status);
1020 return status;
1021}
1022
1023static u32 vfe_var_construct_single(struct gk20a *g,
1024 struct boardobj **ppboardobj,
1025 u16 size, void *pargs)
1026{
1027 struct boardobj *ptmpobj = (struct boardobj *)pargs;
1028 struct vfe_var_single *pvfevar;
1029 u32 status = 0;
1030
1031 gk20a_dbg_info("");
1032
1033 ptmpobj->type_mask |= BIT(CTRL_PERF_VFE_VAR_TYPE_SINGLE);
1034 status = vfe_var_construct_super(g, ppboardobj, size, pargs);
1035 if (status)
1036 return -EINVAL;
1037
1038 pvfevar = (struct vfe_var_single *)*ppboardobj;
1039
1040 pvfevar->super.super.pmudatainit =
1041 _vfe_var_pmudatainit_single;
1042
1043 pvfevar->override_type = CTRL_PERF_VFE_VAR_SINGLE_OVERRIDE_TYPE_NONE;
1044 pvfevar->override_value = 0;
1045
1046 gk20a_dbg_info("Done");
1047 return status;
1048}
diff --git a/drivers/gpu/nvgpu/perf/vfe_var.h b/drivers/gpu/nvgpu/perf/vfe_var.h
new file mode 100644
index 00000000..fc43311b
--- /dev/null
+++ b/drivers/gpu/nvgpu/perf/vfe_var.h
@@ -0,0 +1,97 @@
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 _VFE_VAR_H_
15#define _VFE_VAR_H_
16
17#include "boardobj/boardobjgrp.h"
18#include "pmuif/gpmuifperf.h"
19#include "pmuif/gpmuifperfvfe.h"
20
21u32 vfe_var_sw_setup(struct gk20a *g);
22u32 vfe_var_pmu_setup(struct gk20a *g);
23
24#define VFE_VAR_GET(_pperf, _idx) \
25 ((struct vfe_var)BOARDOBJGRP_OBJ_GET_BY_IDX( \
26 &((_pperf)->vfe.vars.super.super), (_idx)))
27
28#define VFE_VAR_IDX_IS_VALID(_pperf, _idx) \
29 boardobjgrp_idxisvalid(&((_pperf)->vfe.vars.super.super), (_idx))
30
31struct vfe_var {
32 struct boardobj super;
33 u32 out_range_min;
34 u32 out_range_max;
35 bool b_is_dynamic_valid;
36 bool b_is_dynamic;
37};
38
39struct vfe_vars {
40 struct boardobjgrp_e32 super;
41 u8 polling_periodms;
42};
43
44struct vfe_var_derived {
45 struct vfe_var super;
46};
47
48struct vfe_var_derived_product {
49 struct vfe_var_derived super;
50 u8 var_idx0;
51 u8 var_idx1;
52};
53
54struct vfe_var_derived_sum {
55 struct vfe_var_derived super;
56 u8 var_idx0;
57 u8 var_idx1;
58};
59
60struct vfe_var_single {
61 struct vfe_var super;
62 u8 override_type;
63 u32 override_value;
64};
65
66struct vfe_var_single_frequency {
67 struct vfe_var_single super;
68};
69
70struct vfe_var_single_voltage {
71 struct vfe_var_single super;
72};
73
74struct vfe_var_single_sensed {
75 struct vfe_var_single super;
76};
77
78struct vfe_var_single_sensed_fuse {
79 struct vfe_var_single_sensed super;
80 struct nv_pmu_vfe_var_single_sensed_fuse_override_info override_info;
81 struct nv_pmu_vfe_var_single_sensed_fuse_vfield_info vfield_info;
82 struct nv_pmu_vfe_var_single_sensed_fuse_ver_vfield_info vfield_ver_info;
83 u32 fuse_value_integer;
84 u32 fuse_value_hw_integer;
85 u8 fuse_version;
86 bool b_version_check_done;
87};
88
89struct vfe_var_single_sensed_temp {
90 struct vfe_var_single_sensed super;
91 u8 therm_channel_index;
92 int temp_hysteresis_positive;
93 int temp_hysteresis_negative;
94 int temp_default;
95};
96
97#endif
diff --git a/drivers/gpu/nvgpu/pstate/pstate.c b/drivers/gpu/nvgpu/pstate/pstate.c
new file mode 100644
index 00000000..83f17937
--- /dev/null
+++ b/drivers/gpu/nvgpu/pstate/pstate.c
@@ -0,0 +1,101 @@
1/*
2 * general p state infrastructure
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
16#include "gk20a/gk20a.h"
17#include "clk/clk.h"
18#include "perf/perf.h"
19
20/*sw setup for pstate components*/
21int gk20a_init_pstate_support(struct gk20a *g)
22{
23 u32 err;
24
25 gk20a_dbg_fn("");
26
27 err = clk_vin_sw_setup(g);
28 if (err)
29 return err;
30
31 err = clk_fll_sw_setup(g);
32 if (err)
33 return err;
34
35 err = vfe_var_sw_setup(g);
36 if (err)
37 return err;
38
39 err = vfe_equ_sw_setup(g);
40 if (err)
41 return err;
42
43 err = clk_domain_sw_setup(g);
44 if (err)
45 return err;
46
47 err = clk_vf_point_sw_setup(g);
48 if (err)
49 return err;
50
51 err = clk_prog_sw_setup(g);
52 return err;
53}
54
55/*sw setup for pstate components*/
56int gk20a_init_pstate_pmu_support(struct gk20a *g)
57{
58 u32 err;
59
60 gk20a_dbg_fn("");
61
62 err = vfe_var_pmu_setup(g);
63 if (err)
64 return err;
65
66 err = vfe_equ_pmu_setup(g);
67 if (err)
68 return err;
69
70 err = clk_domain_pmu_setup(g);
71 if (err)
72 return err;
73
74 err = clk_prog_pmu_setup(g);
75 if (err)
76 return err;
77
78 err = clk_vin_pmu_setup(g);
79 if (err)
80 return err;
81
82 err = clk_fll_pmu_setup(g);
83 if (err)
84 return err;
85
86 err = clk_vf_point_pmu_setup(g);
87 if (err)
88 return err;
89
90 err = clk_pmu_vin_load(g);
91 if (err)
92 return err;
93
94 err = perf_pmu_vfe_load(g);
95 if (err)
96 return err;
97
98 err = clk_pmu_vf_inject(g);
99 return err;
100}
101
diff --git a/drivers/gpu/nvgpu/pstate/pstate.h b/drivers/gpu/nvgpu/pstate/pstate.h
new file mode 100644
index 00000000..fb49adf3
--- /dev/null
+++ b/drivers/gpu/nvgpu/pstate/pstate.h
@@ -0,0 +1,19 @@
1/*
2 * general p state infrastructure
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
16#include "gk20a/gk20a.h"
17
18int gk20a_init_pstate_support(struct gk20a *g);
19int gk20a_init_pstate_pmu_support(struct gk20a *g);