summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/gp106/sec2_gp106.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/nvgpu/gp106/sec2_gp106.c')
-rw-r--r--drivers/gpu/nvgpu/gp106/sec2_gp106.c388
1 files changed, 388 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/gp106/sec2_gp106.c b/drivers/gpu/nvgpu/gp106/sec2_gp106.c
new file mode 100644
index 00000000..8f34edd1
--- /dev/null
+++ b/drivers/gpu/nvgpu/gp106/sec2_gp106.c
@@ -0,0 +1,388 @@
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 <linux/delay.h> /* for udelay */
15#include <linux/clk.h>
16#include "gk20a/gk20a.h"
17#include "gk20a/pmu_gk20a.h"
18
19#include "gm206/pmu_gm206.h"
20#include "gm20b/pmu_gm20b.h"
21#include "gp10b/pmu_gp10b.h"
22#include "gp106/pmu_gp106.h"
23#include "gp106/acr_gp106.h"
24#include "gp106/hw_mc_gp106.h"
25#include "gp106/hw_pwr_gp106.h"
26#include "gp106/hw_psec_gp106.h"
27#include "sec2_gp106.h"
28#include "acr.h"
29
30/*Defines*/
31#define gm20b_dbg_pmu(fmt, arg...) \
32 gk20a_dbg(gpu_dbg_pmu, fmt, ##arg)
33
34int sec2_clear_halt_interrupt_status(struct gk20a *g, unsigned int timeout)
35{
36 u32 data = 0;
37 unsigned long end_jiffies = jiffies + msecs_to_jiffies(timeout);
38
39 while (time_before(jiffies, end_jiffies) ||
40 !tegra_platform_is_silicon()) {
41 gk20a_writel(g, psec_falcon_irqsclr_r(),
42 gk20a_readl(g, psec_falcon_irqsclr_r()) | (0x10));
43 data = gk20a_readl(g, psec_falcon_irqstat_r());
44 if ((data & psec_falcon_irqstat_halt_true_f()) !=
45 psec_falcon_irqstat_halt_true_f())
46 /*halt irq is clear*/
47 break;
48 timeout--;
49 udelay(1);
50 }
51 if (timeout == 0)
52 return -EBUSY;
53 return 0;
54}
55
56int sec2_wait_for_halt(struct gk20a *g, unsigned int timeout)
57{
58 u32 data = 0;
59 int completion = -EBUSY;
60 unsigned long end_jiffies = jiffies + msecs_to_jiffies(timeout);
61
62 while (time_before(jiffies, end_jiffies) ||
63 !tegra_platform_is_silicon()) {
64 data = gk20a_readl(g, psec_falcon_cpuctl_r());
65 if (data & psec_falcon_cpuctl_halt_intr_m()) {
66 /*CPU is halted break*/
67 completion = 0;
68 break;
69 }
70 udelay(1);
71 }
72 if (completion){
73 gk20a_err(dev_from_gk20a(g), "ACR boot timed out");
74 }
75 else {
76
77 g->acr.capabilities = gk20a_readl(g, psec_falcon_mailbox1_r());
78 gm20b_dbg_pmu("ACR capabilities %x\n", g->acr.capabilities);
79 data = gk20a_readl(g, psec_falcon_mailbox0_r());
80 if (data) {
81
82 gk20a_err(dev_from_gk20a(g),
83 "ACR boot failed, err %x", data);
84 completion = -EAGAIN;
85 }
86 }
87
88 init_pmu_setup_hw1(g);
89
90 return completion;
91}
92
93void sec2_copy_to_dmem(struct pmu_gk20a *pmu,
94 u32 dst, u8 *src, u32 size, u8 port)
95{
96 struct gk20a *g = gk20a_from_pmu(pmu);
97 u32 i, words, bytes;
98 u32 data, addr_mask;
99 u32 *src_u32 = (u32*)src;
100
101 if (size == 0) {
102 gk20a_err(dev_from_gk20a(g),
103 "size is zero");
104 return;
105 }
106
107 if (dst & 0x3) {
108 gk20a_err(dev_from_gk20a(g),
109 "dst (0x%08x) not 4-byte aligned", dst);
110 return;
111 }
112
113 mutex_lock(&pmu->pmu_copy_lock);
114
115 words = size >> 2;
116 bytes = size & 0x3;
117
118 addr_mask = psec_falcon_dmemc_offs_m() |
119 psec_falcon_dmemc_blk_m();
120
121 dst &= addr_mask;
122
123 gk20a_writel(g, psec_falcon_dmemc_r(port),
124 dst | psec_falcon_dmemc_aincw_f(1));
125
126 for (i = 0; i < words; i++)
127 gk20a_writel(g, psec_falcon_dmemd_r(port), src_u32[i]);
128
129 if (bytes > 0) {
130 data = 0;
131 for (i = 0; i < bytes; i++)
132 ((u8 *)&data)[i] = src[(words << 2) + i];
133 gk20a_writel(g, psec_falcon_dmemd_r(port), data);
134 }
135
136 data = gk20a_readl(g, psec_falcon_dmemc_r(port)) & addr_mask;
137 size = ALIGN(size, 4);
138 if (data != dst + size) {
139 gk20a_err(dev_from_gk20a(g),
140 "copy failed. bytes written %d, expected %d",
141 data - dst, size);
142 }
143 mutex_unlock(&pmu->pmu_copy_lock);
144 return;
145}
146
147int bl_bootstrap_sec2(struct pmu_gk20a *pmu,
148 void *desc, u32 bl_sz)
149{
150 struct gk20a *g = gk20a_from_pmu(pmu);
151 struct acr_desc *acr = &g->acr;
152 struct mm_gk20a *mm = &g->mm;
153 u32 imem_dst_blk = 0;
154 u32 virt_addr = 0;
155 u32 tag = 0;
156 u32 index = 0;
157 struct hsflcn_bl_desc *pmu_bl_gm10x_desc = g->acr.pmu_hsbl_desc;
158 u32 *bl_ucode;
159 u32 data = 0;
160
161 gk20a_dbg_fn("");
162
163 /* SEC2 Config */
164 gk20a_writel(g, psec_falcon_itfen_r(),
165 gk20a_readl(g, psec_falcon_itfen_r()) |
166 psec_falcon_itfen_ctxen_enable_f());
167
168 gk20a_writel(g, psec_falcon_nxtctx_r(),
169 pwr_pmu_new_instblk_ptr_f(
170 gk20a_mm_inst_block_addr(g, &mm->pmu.inst_block) >> 12) |
171 pwr_pmu_new_instblk_valid_f(1) |
172 gk20a_aperture_mask(g, &mm->pmu.inst_block,
173 pwr_pmu_new_instblk_target_sys_coh_f(),
174 pwr_pmu_new_instblk_target_fb_f()));
175
176 data = gk20a_readl(g, psec_falcon_debug1_r());
177 data |= psec_falcon_debug1_ctxsw_mode_m();
178 gk20a_writel(g, psec_falcon_debug1_r(), data);
179
180 data = gk20a_readl(g, psec_falcon_engctl_r());
181 data |= (1 << 3);
182 gk20a_writel(g, psec_falcon_engctl_r(), data);
183
184 /* TBD: load all other surfaces */
185 /*copy bootloader interface structure to dmem*/
186 gk20a_writel(g, psec_falcon_dmemc_r(0),
187 psec_falcon_dmemc_offs_f(0) |
188 psec_falcon_dmemc_blk_f(0) |
189 psec_falcon_dmemc_aincw_f(1));
190 sec2_copy_to_dmem(pmu, 0, (u8 *)desc,
191 sizeof(struct flcn_bl_dmem_desc), 0);
192 /*TODO This had to be copied to bl_desc_dmem_load_off, but since
193 * this is 0, so ok for now*/
194
195 /* Now copy bootloader to TOP of IMEM */
196 imem_dst_blk = (psec_falcon_hwcfg_imem_size_v(
197 gk20a_readl(g, psec_falcon_hwcfg_r()))) - bl_sz/256;
198
199 /* Set Auto-Increment on write */
200 gk20a_writel(g, psec_falcon_imemc_r(0),
201 psec_falcon_imemc_offs_f(0) |
202 psec_falcon_imemc_blk_f(imem_dst_blk) |
203 psec_falcon_imemc_aincw_f(1));
204 virt_addr = pmu_bl_gm10x_desc->bl_start_tag << 8;
205 tag = virt_addr >> 8; /* tag is always 256B aligned */
206 bl_ucode = (u32 *)(acr->hsbl_ucode.cpu_va);
207 for (index = 0; index < bl_sz/4; index++) {
208 if ((index % 64) == 0) {
209 gk20a_writel(g, psec_falcon_imemt_r(0),
210 (tag & 0xffff) << 0);
211 tag++;
212 }
213 gk20a_writel(g, psec_falcon_imemd_r(0),
214 bl_ucode[index] & 0xffffffff);
215 }
216 gk20a_writel(g, psec_falcon_imemt_r(0), (0 & 0xffff) << 0);
217
218 gm20b_dbg_pmu("Before starting falcon with BL\n");
219
220 gk20a_writel(g, psec_falcon_mailbox0_r(), 0xDEADA5A5);
221
222 gk20a_writel(g, psec_falcon_bootvec_r(),
223 psec_falcon_bootvec_vec_f(virt_addr));
224
225 gk20a_writel(g, psec_falcon_cpuctl_r(),
226 psec_falcon_cpuctl_startcpu_f(1));
227
228 return 0;
229}
230
231void sec_enable_irq(struct pmu_gk20a *pmu, bool enable)
232{
233 struct gk20a *g = gk20a_from_pmu(pmu);
234
235 gk20a_dbg_fn("");
236
237 gk20a_writel(g, psec_falcon_irqmclr_r(),
238 psec_falcon_irqmclr_gptmr_f(1) |
239 psec_falcon_irqmclr_wdtmr_f(1) |
240 psec_falcon_irqmclr_mthd_f(1) |
241 psec_falcon_irqmclr_ctxsw_f(1) |
242 psec_falcon_irqmclr_halt_f(1) |
243 psec_falcon_irqmclr_exterr_f(1) |
244 psec_falcon_irqmclr_swgen0_f(1) |
245 psec_falcon_irqmclr_swgen1_f(1) |
246 psec_falcon_irqmclr_ext_f(0xff));
247
248 if (enable) {
249 /* dest 0=falcon, 1=host; level 0=irq0, 1=irq1 */
250 gk20a_writel(g, psec_falcon_irqdest_r(),
251 psec_falcon_irqdest_host_gptmr_f(0) |
252 psec_falcon_irqdest_host_wdtmr_f(1) |
253 psec_falcon_irqdest_host_mthd_f(0) |
254 psec_falcon_irqdest_host_ctxsw_f(0) |
255 psec_falcon_irqdest_host_halt_f(1) |
256 psec_falcon_irqdest_host_exterr_f(0) |
257 psec_falcon_irqdest_host_swgen0_f(1) |
258 psec_falcon_irqdest_host_swgen1_f(0) |
259 psec_falcon_irqdest_host_ext_f(0xff) |
260 psec_falcon_irqdest_target_gptmr_f(1) |
261 psec_falcon_irqdest_target_wdtmr_f(0) |
262 psec_falcon_irqdest_target_mthd_f(0) |
263 psec_falcon_irqdest_target_ctxsw_f(0) |
264 psec_falcon_irqdest_target_halt_f(0) |
265 psec_falcon_irqdest_target_exterr_f(0) |
266 psec_falcon_irqdest_target_swgen0_f(0) |
267 psec_falcon_irqdest_target_swgen1_f(1) |
268 psec_falcon_irqdest_target_ext_f(0xff));
269
270 /* 0=disable, 1=enable */
271 gk20a_writel(g, psec_falcon_irqmset_r(),
272 psec_falcon_irqmset_gptmr_f(1) |
273 psec_falcon_irqmset_wdtmr_f(1) |
274 psec_falcon_irqmset_mthd_f(0) |
275 psec_falcon_irqmset_ctxsw_f(0) |
276 psec_falcon_irqmset_halt_f(1) |
277 psec_falcon_irqmset_exterr_f(1) |
278 psec_falcon_irqmset_swgen0_f(1) |
279 psec_falcon_irqmset_swgen1_f(1));
280
281 }
282
283 gk20a_dbg_fn("done");
284}
285
286void init_pmu_setup_hw1(struct gk20a *g)
287{
288 struct mm_gk20a *mm = &g->mm;
289 struct pmu_gk20a *pmu = &g->pmu;
290 struct gk20a_platform *platform = dev_get_drvdata(g->dev);
291
292 /* PMU TRANSCFG */
293 /* setup apertures - virtual */
294 gk20a_writel(g, pwr_fbif_transcfg_r(GK20A_PMU_DMAIDX_UCODE),
295 pwr_fbif_transcfg_mem_type_physical_f() |
296 pwr_fbif_transcfg_target_local_fb_f());
297 gk20a_writel(g, pwr_fbif_transcfg_r(GK20A_PMU_DMAIDX_VIRT),
298 pwr_fbif_transcfg_mem_type_virtual_f());
299 /* setup apertures - physical */
300 gk20a_writel(g, pwr_fbif_transcfg_r(GK20A_PMU_DMAIDX_PHYS_VID),
301 pwr_fbif_transcfg_mem_type_physical_f() |
302 pwr_fbif_transcfg_target_local_fb_f());
303 gk20a_writel(g, pwr_fbif_transcfg_r(GK20A_PMU_DMAIDX_PHYS_SYS_COH),
304 pwr_fbif_transcfg_mem_type_physical_f() |
305 pwr_fbif_transcfg_target_coherent_sysmem_f());
306 gk20a_writel(g, pwr_fbif_transcfg_r(GK20A_PMU_DMAIDX_PHYS_SYS_NCOH),
307 pwr_fbif_transcfg_mem_type_physical_f() |
308 pwr_fbif_transcfg_target_noncoherent_sysmem_f());
309
310 /* PMU Config */
311 gk20a_writel(g, pwr_falcon_itfen_r(),
312 gk20a_readl(g, pwr_falcon_itfen_r()) |
313 pwr_falcon_itfen_ctxen_enable_f());
314 gk20a_writel(g, pwr_pmu_new_instblk_r(),
315 pwr_pmu_new_instblk_ptr_f(
316 gk20a_mm_inst_block_addr(g, &mm->pmu.inst_block) >> 12) |
317 pwr_pmu_new_instblk_valid_f(1) |
318 gk20a_aperture_mask(g, &mm->pmu.inst_block,
319 pwr_pmu_new_instblk_target_sys_coh_f(),
320 pwr_pmu_new_instblk_target_fb_f()));
321
322 /*Copying pmu cmdline args*/
323 g->ops.pmu_ver.set_pmu_cmdline_args_cpu_freq(pmu,
324 clk_get_rate(platform->clk[1]));
325 g->ops.pmu_ver.set_pmu_cmdline_args_secure_mode(pmu, 1);
326 g->ops.pmu_ver.set_pmu_cmdline_args_trace_size(
327 pmu, GK20A_PMU_TRACE_BUFSIZE);
328 g->ops.pmu_ver.set_pmu_cmdline_args_trace_dma_base(pmu);
329 g->ops.pmu_ver.set_pmu_cmdline_args_trace_dma_idx(
330 pmu, GK20A_PMU_DMAIDX_VIRT);
331
332 pmu_copy_to_dmem(pmu, g->acr.pmu_args,
333 (u8 *)(g->ops.pmu_ver.get_pmu_cmdline_args_ptr(pmu)),
334 g->ops.pmu_ver.get_pmu_cmdline_args_size(pmu), 0);
335
336}
337
338int init_sec2_setup_hw1(struct gk20a *g,
339 void *desc, u32 bl_sz)
340{
341 struct pmu_gk20a *pmu = &g->pmu;
342 int err;
343 u32 data = 0;
344
345 gk20a_dbg_fn("");
346
347 mutex_lock(&pmu->isr_mutex);
348 g->ops.pmu.reset(g);
349 pmu->isr_enabled = true;
350 mutex_unlock(&pmu->isr_mutex);
351
352 data = gk20a_readl(g, psec_fbif_ctl_r());
353 data |= psec_fbif_ctl_allow_phys_no_ctx_allow_f();
354 gk20a_writel(g, psec_fbif_ctl_r(), data);
355
356 data = gk20a_readl(g, psec_falcon_dmactl_r());
357 data &= ~(psec_falcon_dmactl_require_ctx_f(1));
358 gk20a_writel(g, psec_falcon_dmactl_r(), data);
359
360 /* setup apertures - virtual */
361 gk20a_writel(g, psec_fbif_transcfg_r(GK20A_PMU_DMAIDX_UCODE),
362 psec_fbif_transcfg_mem_type_physical_f() |
363 psec_fbif_transcfg_target_local_fb_f());
364 gk20a_writel(g, psec_fbif_transcfg_r(GK20A_PMU_DMAIDX_VIRT),
365 psec_fbif_transcfg_mem_type_virtual_f());
366 /* setup apertures - physical */
367 gk20a_writel(g, psec_fbif_transcfg_r(GK20A_PMU_DMAIDX_PHYS_VID),
368 psec_fbif_transcfg_mem_type_physical_f() |
369 psec_fbif_transcfg_target_local_fb_f());
370 gk20a_writel(g, psec_fbif_transcfg_r(GK20A_PMU_DMAIDX_PHYS_SYS_COH),
371 psec_fbif_transcfg_mem_type_physical_f() |
372 psec_fbif_transcfg_target_coherent_sysmem_f());
373 gk20a_writel(g, psec_fbif_transcfg_r(GK20A_PMU_DMAIDX_PHYS_SYS_NCOH),
374 psec_fbif_transcfg_mem_type_physical_f() |
375 psec_fbif_transcfg_target_noncoherent_sysmem_f());
376
377 /*disable irqs for hs falcon booting as we will poll for halt*/
378 mutex_lock(&pmu->isr_mutex);
379 pmu_enable_irq(pmu, false);
380 sec_enable_irq(pmu, false);
381 pmu->isr_enabled = false;
382 mutex_unlock(&pmu->isr_mutex);
383 err = bl_bootstrap_sec2(pmu, desc, bl_sz);
384 if (err)
385 return err;
386
387 return 0;
388}