diff options
Diffstat (limited to 'drivers/gpu/nvgpu/gp106/sec2_gp106.c')
-rw-r--r-- | drivers/gpu/nvgpu/gp106/sec2_gp106.c | 388 |
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 | |||
34 | int 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 | |||
56 | int 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 | |||
93 | void 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 | |||
147 | int 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 | |||
231 | void 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 | |||
286 | void 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 | |||
338 | int 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 | } | ||