summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/gk20a/bus_gk20a.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/nvgpu/gk20a/bus_gk20a.c')
-rw-r--r--drivers/gpu/nvgpu/gk20a/bus_gk20a.c156
1 files changed, 156 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/bus_gk20a.c b/drivers/gpu/nvgpu/gk20a/bus_gk20a.c
new file mode 100644
index 00000000..fda1f80e
--- /dev/null
+++ b/drivers/gpu/nvgpu/gk20a/bus_gk20a.c
@@ -0,0 +1,156 @@
1/*
2 * Copyright (c) 2017, 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 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include <soc/tegra/chip-id.h>
18
19#include <nvgpu/page_allocator.h>
20
21#include "gk20a.h"
22
23#include <nvgpu/hw/gk20a/hw_bus_gk20a.h>
24#include <nvgpu/hw/gk20a/hw_mc_gk20a.h>
25#include <nvgpu/hw/gk20a/hw_gr_gk20a.h>
26#include <nvgpu/hw/gk20a/hw_timer_gk20a.h>
27
28void gk20a_bus_init_hw(struct gk20a *g)
29{
30 struct gk20a_platform *platform = gk20a_get_platform(g->dev);
31
32 /* enable pri timeout only on silicon */
33 if (tegra_platform_is_silicon()) {
34 gk20a_writel(g,
35 timer_pri_timeout_r(),
36 timer_pri_timeout_period_f(
37 platform->default_pri_timeout ?
38 platform->default_pri_timeout :
39 0x186A0) |
40 timer_pri_timeout_en_en_enabled_f());
41 } else {
42 gk20a_writel(g,
43 timer_pri_timeout_r(),
44 timer_pri_timeout_period_f(0x186A0) |
45 timer_pri_timeout_en_en_disabled_f());
46 }
47
48 if (!tegra_platform_is_silicon())
49 gk20a_writel(g, bus_intr_en_0_r(), 0x0);
50 else
51 gk20a_writel(g, bus_intr_en_0_r(),
52 bus_intr_en_0_pri_squash_m() |
53 bus_intr_en_0_pri_fecserr_m() |
54 bus_intr_en_0_pri_timeout_m());
55}
56
57void gk20a_bus_isr(struct gk20a *g)
58{
59 u32 val, err_code;
60 val = gk20a_readl(g, bus_intr_0_r());
61 if (val & (bus_intr_0_pri_squash_m() |
62 bus_intr_0_pri_fecserr_m() |
63 bus_intr_0_pri_timeout_m())) {
64 gk20a_dbg(gpu_dbg_intr, "pmc_enable : 0x%x",
65 gk20a_readl(g, mc_enable_r()));
66 gk20a_dbg(gpu_dbg_intr, "NV_PBUS_INTR_0 : 0x%x", val);
67 gk20a_dbg(gpu_dbg_intr,
68 "NV_PTIMER_PRI_TIMEOUT_SAVE_0: 0x%x\n",
69 gk20a_readl(g, timer_pri_timeout_save_0_r()));
70 gk20a_dbg(gpu_dbg_intr,
71 "NV_PTIMER_PRI_TIMEOUT_SAVE_1: 0x%x\n",
72 gk20a_readl(g, timer_pri_timeout_save_1_r()));
73 err_code = gk20a_readl(g, timer_pri_timeout_fecs_errcode_r());
74 gk20a_dbg(gpu_dbg_intr,
75 "NV_PTIMER_PRI_TIMEOUT_FECS_ERRCODE: 0x%x\n",
76 err_code);
77 if (err_code == 0xbadf13)
78 gk20a_dbg(gpu_dbg_intr,
79 "NV_PGRAPH_PRI_GPC0_GPCCS_FS_GPC: 0x%x\n",
80 gk20a_readl(g, gr_gpc0_fs_gpc_r()));
81
82 gk20a_writel(g, timer_pri_timeout_save_0_r(), 0);
83 gk20a_writel(g, timer_pri_timeout_save_1_r(), 0);
84 }
85
86 if (val)
87 gk20a_dbg(gpu_dbg_intr,
88 "Unhandled pending pbus interrupt\n");
89
90 gk20a_writel(g, bus_intr_0_r(), val);
91}
92
93int gk20a_read_ptimer(struct gk20a *g, u64 *value)
94{
95 const unsigned int max_iterations = 3;
96 unsigned int i = 0;
97 u32 gpu_timestamp_hi_prev = 0;
98
99 if (!value)
100 return -EINVAL;
101
102 /* Note. The GPU nanosecond timer consists of two 32-bit
103 * registers (high & low). To detect a possible low register
104 * wrap-around between the reads, we need to read the high
105 * register before and after low. The wraparound happens
106 * approximately once per 4 secs. */
107
108 /* get initial gpu_timestamp_hi value */
109 gpu_timestamp_hi_prev = gk20a_readl(g, timer_time_1_r());
110
111 for (i = 0; i < max_iterations; ++i) {
112 u32 gpu_timestamp_hi = 0;
113 u32 gpu_timestamp_lo = 0;
114
115 gpu_timestamp_lo = gk20a_readl(g, timer_time_0_r());
116 gpu_timestamp_hi = gk20a_readl(g, timer_time_1_r());
117
118 if (gpu_timestamp_hi == gpu_timestamp_hi_prev) {
119 *value = (((u64)gpu_timestamp_hi) << 32) |
120 gpu_timestamp_lo;
121 return 0;
122 }
123
124 /* wrap-around detected, retry */
125 gpu_timestamp_hi_prev = gpu_timestamp_hi;
126 }
127
128 /* too many iterations, bail out */
129 gk20a_err(dev_from_gk20a(g), "failed to read ptimer");
130 return -EBUSY;
131}
132
133static int gk20a_bus_bar1_bind(struct gk20a *g, struct mem_desc *bar1_inst)
134{
135 u64 iova = gk20a_mm_inst_block_addr(g, bar1_inst);
136 u32 ptr_v = (u32)(iova >> bar1_instance_block_shift_gk20a());
137
138 gk20a_dbg_info("bar1 inst block ptr: 0x%08x", ptr_v);
139
140 gk20a_writel(g, bus_bar1_block_r(),
141 gk20a_aperture_mask(g, bar1_inst,
142 bus_bar1_block_target_sys_mem_ncoh_f(),
143 bus_bar1_block_target_vid_mem_f()) |
144 bus_bar1_block_mode_virtual_f() |
145 bus_bar1_block_ptr_f(ptr_v));
146
147 return 0;
148}
149
150void gk20a_init_bus(struct gpu_ops *gops)
151{
152 gops->bus.init_hw = gk20a_bus_init_hw;
153 gops->bus.isr = gk20a_bus_isr;
154 gops->bus.read_ptimer = gk20a_read_ptimer;
155 gops->bus.bar1_bind = gk20a_bus_bar1_bind;
156}