aboutsummaryrefslogtreecommitdiffstats
path: root/include/gk20a/flcn_gk20a.c
diff options
context:
space:
mode:
Diffstat (limited to 'include/gk20a/flcn_gk20a.c')
-rw-r--r--include/gk20a/flcn_gk20a.c759
1 files changed, 759 insertions, 0 deletions
diff --git a/include/gk20a/flcn_gk20a.c b/include/gk20a/flcn_gk20a.c
new file mode 100644
index 0000000..fdcaef9
--- /dev/null
+++ b/include/gk20a/flcn_gk20a.c
@@ -0,0 +1,759 @@
1/*
2 * Copyright (c) 2017-2018, NVIDIA CORPORATION. All rights reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
21 */
22#include <nvgpu/falcon.h>
23#include <nvgpu/pmu.h>
24#include <nvgpu/io.h>
25
26#include "gk20a/gk20a.h"
27#include "gk20a/flcn_gk20a.h"
28
29#include <nvgpu/hw/gm20b/hw_falcon_gm20b.h>
30
31static int gk20a_flcn_reset(struct nvgpu_falcon *flcn)
32{
33 struct gk20a *g = flcn->g;
34 u32 base_addr = flcn->flcn_base;
35 u32 unit_status = 0;
36 int status = 0;
37
38 if (flcn->flcn_engine_dep_ops.reset_eng) {
39 /* falcon & engine reset */
40 status = flcn->flcn_engine_dep_ops.reset_eng(g);
41 } else {
42 /* do falcon CPU hard reset */
43 unit_status = gk20a_readl(g, base_addr +
44 falcon_falcon_cpuctl_r());
45 gk20a_writel(g, base_addr + falcon_falcon_cpuctl_r(),
46 (unit_status | falcon_falcon_cpuctl_hreset_f(1)));
47 }
48
49 return status;
50}
51
52static bool gk20a_flcn_clear_halt_interrupt_status(struct nvgpu_falcon *flcn)
53{
54 struct gk20a *g = flcn->g;
55 u32 base_addr = flcn->flcn_base;
56 u32 data = 0;
57 bool status = false;
58
59 gk20a_writel(g, base_addr + falcon_falcon_irqsclr_r(),
60 gk20a_readl(g, base_addr + falcon_falcon_irqsclr_r()) |
61 (0x10));
62 data = gk20a_readl(g, (base_addr + falcon_falcon_irqstat_r()));
63
64 if ((data & falcon_falcon_irqstat_halt_true_f()) !=
65 falcon_falcon_irqstat_halt_true_f()) {
66 /*halt irq is clear*/
67 status = true;
68 }
69
70 return status;
71}
72
73static void gk20a_flcn_set_irq(struct nvgpu_falcon *flcn, bool enable)
74{
75 struct gk20a *g = flcn->g;
76 u32 base_addr = flcn->flcn_base;
77
78 if (!flcn->is_interrupt_enabled) {
79 nvgpu_warn(g, "Interrupt not supported on flcn 0x%x ",
80 flcn->flcn_id);
81 /* Keep interrupt disabled */
82 enable = false;
83 }
84
85 if (enable) {
86 gk20a_writel(g, base_addr + falcon_falcon_irqmset_r(),
87 flcn->intr_mask);
88 gk20a_writel(g, base_addr + falcon_falcon_irqdest_r(),
89 flcn->intr_dest);
90 } else {
91 gk20a_writel(g, base_addr + falcon_falcon_irqmclr_r(),
92 0xffffffff);
93 }
94}
95
96static bool gk20a_is_falcon_cpu_halted(struct nvgpu_falcon *flcn)
97{
98 struct gk20a *g = flcn->g;
99 u32 base_addr = flcn->flcn_base;
100
101 return (gk20a_readl(g, base_addr + falcon_falcon_cpuctl_r()) &
102 falcon_falcon_cpuctl_halt_intr_m() ?
103 true : false);
104}
105
106static bool gk20a_is_falcon_idle(struct nvgpu_falcon *flcn)
107{
108 struct gk20a *g = flcn->g;
109 u32 base_addr = flcn->flcn_base;
110 u32 unit_status = 0;
111 bool status = false;
112
113 unit_status = gk20a_readl(g,
114 base_addr + falcon_falcon_idlestate_r());
115
116 if (falcon_falcon_idlestate_falcon_busy_v(unit_status) == 0 &&
117 falcon_falcon_idlestate_ext_busy_v(unit_status) == 0) {
118 status = true;
119 } else {
120 status = false;
121 }
122
123 return status;
124}
125
126static bool gk20a_is_falcon_scrubbing_done(struct nvgpu_falcon *flcn)
127{
128 struct gk20a *g = flcn->g;
129 u32 base_addr = flcn->flcn_base;
130 u32 unit_status = 0;
131 bool status = false;
132
133 unit_status = gk20a_readl(g,
134 base_addr + falcon_falcon_dmactl_r());
135
136 if (unit_status & (falcon_falcon_dmactl_dmem_scrubbing_m() |
137 falcon_falcon_dmactl_imem_scrubbing_m())) {
138 status = false;
139 } else {
140 status = true;
141 }
142
143 return status;
144}
145
146static u32 gk20a_falcon_get_mem_size(struct nvgpu_falcon *flcn,
147 enum flcn_mem_type mem_type)
148{
149 struct gk20a *g = flcn->g;
150 u32 mem_size = 0;
151 u32 hw_cfg_reg = gk20a_readl(g,
152 flcn->flcn_base + falcon_falcon_hwcfg_r());
153
154 if (mem_type == MEM_DMEM) {
155 mem_size = falcon_falcon_hwcfg_dmem_size_v(hw_cfg_reg)
156 << GK20A_PMU_DMEM_BLKSIZE2;
157 } else {
158 mem_size = falcon_falcon_hwcfg_imem_size_v(hw_cfg_reg)
159 << GK20A_PMU_DMEM_BLKSIZE2;
160 }
161
162 return mem_size;
163}
164
165static int flcn_mem_overflow_check(struct nvgpu_falcon *flcn,
166 u32 offset, u32 size, enum flcn_mem_type mem_type)
167{
168 struct gk20a *g = flcn->g;
169 u32 mem_size = 0;
170
171 if (size == 0) {
172 nvgpu_err(g, "size is zero");
173 return -EINVAL;
174 }
175
176 if (offset & 0x3) {
177 nvgpu_err(g, "offset (0x%08x) not 4-byte aligned", offset);
178 return -EINVAL;
179 }
180
181 mem_size = gk20a_falcon_get_mem_size(flcn, mem_type);
182 if (!(offset <= mem_size && (offset + size) <= mem_size)) {
183 nvgpu_err(g, "flcn-id 0x%x, copy overflow ",
184 flcn->flcn_id);
185 nvgpu_err(g, "total size 0x%x, offset 0x%x, copy size 0x%x",
186 mem_size, offset, size);
187 return -EINVAL;
188 }
189
190 return 0;
191}
192
193static int gk20a_flcn_copy_from_dmem(struct nvgpu_falcon *flcn,
194 u32 src, u8 *dst, u32 size, u8 port)
195{
196 struct gk20a *g = flcn->g;
197 u32 base_addr = flcn->flcn_base;
198 u32 i, words, bytes;
199 u32 data, addr_mask;
200 u32 *dst_u32 = (u32 *)dst;
201
202 nvgpu_log_fn(g, " src dmem offset - %x, size - %x", src, size);
203
204 if (flcn_mem_overflow_check(flcn, src, size, MEM_DMEM)) {
205 nvgpu_err(g, "incorrect parameters");
206 return -EINVAL;
207 }
208
209 nvgpu_mutex_acquire(&flcn->copy_lock);
210
211 words = size >> 2;
212 bytes = size & 0x3;
213
214 addr_mask = falcon_falcon_dmemc_offs_m() |
215 falcon_falcon_dmemc_blk_m();
216
217 src &= addr_mask;
218
219 gk20a_writel(g, base_addr + falcon_falcon_dmemc_r(port),
220 src | falcon_falcon_dmemc_aincr_f(1));
221
222 for (i = 0; i < words; i++) {
223 dst_u32[i] = gk20a_readl(g,
224 base_addr + falcon_falcon_dmemd_r(port));