aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/tegra/host/gr3d/gr3d_t30.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/tegra/host/gr3d/gr3d_t30.c')
-rw-r--r--drivers/video/tegra/host/gr3d/gr3d_t30.c435
1 files changed, 435 insertions, 0 deletions
diff --git a/drivers/video/tegra/host/gr3d/gr3d_t30.c b/drivers/video/tegra/host/gr3d/gr3d_t30.c
new file mode 100644
index 00000000000..e7329e50e3d
--- /dev/null
+++ b/drivers/video/tegra/host/gr3d/gr3d_t30.c
@@ -0,0 +1,435 @@
1/*
2 * drivers/video/tegra/host/gr3d/gr3d_t30.c
3 *
4 * Tegra Graphics Host 3D for Tegra3
5 *
6 * Copyright (c) 2011-2012 NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include "nvhost_hwctx.h"
22#include "dev.h"
23#include "host1x/host1x_hardware.h"
24#include "host1x/host1x_syncpt.h"
25#include "gr3d.h"
26
27#include <mach/gpufuse.h>
28#include <mach/hardware.h>
29#include <linux/slab.h>
30
31/* 99 > 2, which makes kernel panic if register set is incorrect */
32static int register_sets = 99;
33
34static const struct hwctx_reginfo ctxsave_regs_3d_global[] = {
35 HWCTX_REGINFO(0xe00, 4, DIRECT),
36 HWCTX_REGINFO(0xe05, 30, DIRECT),
37 HWCTX_REGINFO(0xe25, 2, DIRECT),
38 HWCTX_REGINFO(0xe28, 2, DIRECT),
39 HWCTX_REGINFO(0xe30, 16, DIRECT),
40 HWCTX_REGINFO(0x001, 2, DIRECT),
41 HWCTX_REGINFO(0x00c, 10, DIRECT),
42 HWCTX_REGINFO(0x100, 34, DIRECT),
43 HWCTX_REGINFO(0x124, 2, DIRECT),
44 HWCTX_REGINFO(0x200, 5, DIRECT),
45 HWCTX_REGINFO(0x205, 1024, INDIRECT),
46 HWCTX_REGINFO(0x207, 1024, INDIRECT),
47 HWCTX_REGINFO(0x209, 1, DIRECT),
48 HWCTX_REGINFO(0x300, 64, DIRECT),
49 HWCTX_REGINFO(0x343, 25, DIRECT),
50 HWCTX_REGINFO(0x363, 2, DIRECT),
51 HWCTX_REGINFO(0x400, 16, DIRECT),
52 HWCTX_REGINFO(0x411, 1, DIRECT),
53 HWCTX_REGINFO(0x412, 1, DIRECT),
54 HWCTX_REGINFO(0x500, 4, DIRECT),
55 HWCTX_REGINFO(0x520, 32, DIRECT),
56 HWCTX_REGINFO(0x540, 64, INDIRECT),
57 HWCTX_REGINFO(0x600, 16, INDIRECT_4X),
58 HWCTX_REGINFO(0x603, 128, INDIRECT),
59 HWCTX_REGINFO(0x608, 4, DIRECT),
60 HWCTX_REGINFO(0x60e, 1, DIRECT),
61 HWCTX_REGINFO(0x700, 64, INDIRECT),
62 HWCTX_REGINFO(0x710, 50, DIRECT),
63 HWCTX_REGINFO(0x750, 16, DIRECT),
64 HWCTX_REGINFO(0x800, 16, INDIRECT_4X),
65 HWCTX_REGINFO(0x803, 512, INDIRECT),
66 HWCTX_REGINFO(0x805, 64, INDIRECT),
67 HWCTX_REGINFO(0x820, 32, DIRECT),
68 HWCTX_REGINFO(0x900, 64, INDIRECT),
69 HWCTX_REGINFO(0x902, 2, DIRECT),
70 HWCTX_REGINFO(0x90a, 1, DIRECT),
71 HWCTX_REGINFO(0xa02, 10, DIRECT),
72 HWCTX_REGINFO(0xb04, 1, DIRECT),
73 HWCTX_REGINFO(0xb06, 13, DIRECT),
74 HWCTX_REGINFO(0xe42, 2, DIRECT), /* HW bug workaround */
75};
76
77static const struct hwctx_reginfo ctxsave_regs_3d_perset[] = {
78 HWCTX_REGINFO(0xe04, 1, DIRECT),
79 HWCTX_REGINFO(0xe2a, 1, DIRECT),
80 HWCTX_REGINFO(0x413, 1, DIRECT),
81 HWCTX_REGINFO(0x90b, 1, DIRECT),
82 HWCTX_REGINFO(0xe41, 1, DIRECT),
83};
84
85static unsigned int restore_set1_offset;
86
87#define SAVE_BEGIN_V1_SIZE (1 + RESTORE_BEGIN_SIZE)
88#define SAVE_DIRECT_V1_SIZE (4 + RESTORE_DIRECT_SIZE)
89#define SAVE_INDIRECT_V1_SIZE (6 + RESTORE_INDIRECT_SIZE)
90#define SAVE_END_V1_SIZE (9 + RESTORE_END_SIZE)
91#define SAVE_INCRS 3
92#define SAVE_THRESH_OFFSET 0
93#define RESTORE_BEGIN_SIZE 4
94#define RESTORE_DIRECT_SIZE 1
95#define RESTORE_INDIRECT_SIZE 2
96#define RESTORE_END_SIZE 1
97
98struct save_info {
99 u32 *ptr;
100 unsigned int save_count;
101 unsigned int restore_count;
102 unsigned int save_incrs;
103 unsigned int restore_incrs;
104};
105
106/*** v1 saver ***/
107
108static void save_push_v1(struct nvhost_hwctx *nctx, struct nvhost_cdma *cdma)
109{
110 struct host1x_hwctx *ctx = to_host1x_hwctx(nctx);
111 struct host1x_hwctx_handler *p = host1x_hwctx_handler(ctx);
112
113 /* wait for 3d idle */
114 nvhost_cdma_push(cdma,
115 nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0),
116 nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_OP_DONE,
117 p->syncpt));
118 nvhost_cdma_push(cdma,
119 nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
120 NV_CLASS_HOST_WAIT_SYNCPT_BASE, 1),
121 nvhost_class_host_wait_syncpt_base(p->syncpt,
122 p->waitbase, 1));
123 /* back to 3d */
124 nvhost_cdma_push(cdma,
125 nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0),
126 NVHOST_OPCODE_NOOP);
127 /* set register set 0 and 1 register read memory output addresses,
128 and send their reads to memory */
129 if (register_sets == 2) {
130 nvhost_cdma_push(cdma,
131 nvhost_opcode_imm(AR3D_GSHIM_WRITE_MASK, 2),
132 nvhost_opcode_imm(AR3D_GLOBAL_MEMORY_OUTPUT_READS,
133 1));
134 nvhost_cdma_push(cdma,
135 nvhost_opcode_nonincr(0x904, 1),
136 ctx->restore_phys + restore_set1_offset * 4);
137 }
138 nvhost_cdma_push(cdma,
139 nvhost_opcode_imm(AR3D_GSHIM_WRITE_MASK, 1),
140 nvhost_opcode_imm(AR3D_GLOBAL_MEMORY_OUTPUT_READS, 1));
141 nvhost_cdma_push(cdma,
142 nvhost_opcode_nonincr(AR3D_DW_MEMORY_OUTPUT_ADDRESS, 1),
143 ctx->restore_phys);
144 /* gather the save buffer */
145 nvhost_cdma_push_gather(cdma,
146 (void *)NVHOST_CDMA_PUSH_GATHER_CTXSAVE,
147 (void *)NVHOST_CDMA_PUSH_GATHER_CTXSAVE,
148 nvhost_opcode_gather(p->save_size),
149 p->save_phys);
150}
151
152static void __init save_begin_v1(struct host1x_hwctx_handler *p, u32 *ptr)
153{
154 ptr[0] = nvhost_opcode_nonincr(AR3D_DW_MEMORY_OUTPUT_DATA,
155 RESTORE_BEGIN_SIZE);
156 nvhost_3dctx_restore_begin(p, ptr + 1);
157 ptr += RESTORE_BEGIN_SIZE;
158}
159
160static void __init save_direct_v1(u32 *ptr, u32 start_reg, u32 count)
161{
162 ptr[0] = nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID,
163 AR3D_DW_MEMORY_OUTPUT_DATA, 1);
164 nvhost_3dctx_restore_direct(ptr + 1, start_reg, count);
165 ptr += RESTORE_DIRECT_SIZE;
166 ptr[1] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
167 NV_CLASS_HOST_INDOFF, 1);
168 ptr[2] = nvhost_class_host_indoff_reg_read(NV_HOST_MODULE_GR3D,
169 start_reg, true);
170 /* TODO could do this in the setclass if count < 6 */
171 ptr[3] = nvhost_opcode_nonincr(NV_CLASS_HOST_INDDATA, count);
172}
173
174static void __init save_indirect_v1(u32 *ptr, u32 offset_reg, u32 offset,
175 u32 data_reg, u32 count)
176{
177 ptr[0] = nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0);
178 ptr[1] = nvhost_opcode_nonincr(AR3D_DW_MEMORY_OUTPUT_DATA,
179 RESTORE_INDIRECT_SIZE);
180 nvhost_3dctx_restore_indirect(ptr + 2, offset_reg, offset, data_reg,
181 count);
182 ptr += RESTORE_INDIRECT_SIZE;
183 ptr[2] = nvhost_opcode_imm(offset_reg, offset);
184 ptr[3] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
185 NV_CLASS_HOST_INDOFF, 1);
186 ptr[4] = nvhost_class_host_indoff_reg_read(NV_HOST_MODULE_GR3D,
187 data_reg, false);
188 ptr[5] = nvhost_opcode_nonincr(NV_CLASS_HOST_INDDATA, count);
189}
190
191static void __init save_end_v1(struct host1x_hwctx_handler *p, u32 *ptr)
192{
193 /* write end of restore buffer */
194 ptr[0] = nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID,
195 AR3D_DW_MEMORY_OUTPUT_DATA, 1);
196 nvhost_3dctx_restore_end(p, ptr + 1);
197 ptr += RESTORE_END_SIZE;
198 /* reset to dual reg if necessary */
199 ptr[1] = nvhost_opcode_imm(AR3D_GSHIM_WRITE_MASK,
200 (1 << register_sets) - 1);
201 /* op_done syncpt incr to flush FDC */
202 ptr[2] = nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_OP_DONE, p->syncpt);
203 /* host wait for that syncpt incr, and advance the wait base */
204 ptr[3] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
205 NV_CLASS_HOST_WAIT_SYNCPT_BASE,
206 nvhost_mask2(
207 NV_CLASS_HOST_WAIT_SYNCPT_BASE,
208 NV_CLASS_HOST_INCR_SYNCPT_BASE));
209 ptr[4] = nvhost_class_host_wait_syncpt_base(p->syncpt,
210 p->waitbase, p->save_incrs - 1);
211 ptr[5] = nvhost_class_host_incr_syncpt_base(p->waitbase,
212 p->save_incrs);
213 /* set class back to 3d */
214 ptr[6] = nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0);
215 /* send reg reads back to host */
216 ptr[7] = nvhost_opcode_imm(AR3D_GLOBAL_MEMORY_OUTPUT_READS, 0);
217 /* final syncpt increment to release waiters */
218 ptr[8] = nvhost_opcode_imm(0, p->syncpt);
219}
220
221/*** save ***/
222
223
224
225static void __init setup_save_regs(struct save_info *info,
226 const struct hwctx_reginfo *regs,
227 unsigned int nr_regs)
228{
229 const struct hwctx_reginfo *rend = regs + nr_regs;
230 u32 *ptr = info->ptr;
231 unsigned int save_count = info->save_count;
232 unsigned int restore_count = info->restore_count;
233
234 for ( ; regs != rend; ++regs) {
235 u32 offset = regs->offset;
236 u32 count = regs->count;
237 u32 indoff = offset + 1;
238 switch (regs->type) {
239 case HWCTX_REGINFO_DIRECT:
240 if (ptr) {
241 save_direct_v1(ptr, offset, count);
242 ptr += SAVE_DIRECT_V1_SIZE;
243 }
244 save_count += SAVE_DIRECT_V1_SIZE;
245 restore_count += RESTORE_DIRECT_SIZE;
246 break;
247 case HWCTX_REGINFO_INDIRECT_4X:
248 ++indoff;
249 /* fall through */
250 case HWCTX_REGINFO_INDIRECT:
251 if (ptr) {
252 save_indirect_v1(ptr, offset, 0,
253 indoff, count);
254 ptr += SAVE_INDIRECT_V1_SIZE;
255 }
256 save_count += SAVE_INDIRECT_V1_SIZE;
257 restore_count += RESTORE_INDIRECT_SIZE;
258 break;
259 }
260 if (ptr) {
261 /* SAVE cases only: reserve room for incoming data */
262 u32 k = 0;
263 /*
264 * Create a signature pattern for indirect data (which
265 * will be overwritten by true incoming data) for
266 * better deducing where we are in a long command
267 * sequence, when given only a FIFO snapshot for debug
268 * purposes.
269 */
270 for (k = 0; k < count; k++)
271 *(ptr + k) = 0xd000d000 | (offset << 16) | k;
272 ptr += count;
273 }
274 save_count += count;
275 restore_count += count;
276 }
277
278 info->ptr = ptr;
279 info->save_count = save_count;
280 info->restore_count = restore_count;
281}
282
283static void __init switch_gpu(struct save_info *info,
284 unsigned int save_src_set,
285 u32 save_dest_sets,
286 u32 restore_dest_sets)
287{
288 if (info->ptr) {
289 info->ptr[0] = nvhost_opcode_setclass(
290 NV_GRAPHICS_3D_CLASS_ID,
291 AR3D_DW_MEMORY_OUTPUT_DATA, 1);
292 info->ptr[1] = nvhost_opcode_imm(AR3D_GSHIM_WRITE_MASK,
293 restore_dest_sets);
294 info->ptr[2] = nvhost_opcode_imm(AR3D_GSHIM_WRITE_MASK,
295 save_dest_sets);
296 info->ptr[3] = nvhost_opcode_imm(AR3D_GSHIM_READ_SELECT,
297 save_src_set);
298 info->ptr += 4;
299 }
300 info->save_count += 4;
301 info->restore_count += 1;
302}
303
304static void __init setup_save(struct host1x_hwctx_handler *p, u32 *ptr)
305{
306 struct save_info info = {
307 ptr,
308 SAVE_BEGIN_V1_SIZE,
309 RESTORE_BEGIN_SIZE,
310 SAVE_INCRS,
311 1
312 };
313 int save_end_size = SAVE_END_V1_SIZE;
314
315 BUG_ON(register_sets > 2);
316
317 if (info.ptr) {
318 save_begin_v1(p, info.ptr);
319 info.ptr += SAVE_BEGIN_V1_SIZE;
320 }
321
322 /* read from set0, write cmds through set0, restore to set0 and 1 */
323 if (register_sets == 2)
324 switch_gpu(&info, 0, 1, 3);
325
326 /* save regs that are common to both sets */
327 setup_save_regs(&info,
328 ctxsave_regs_3d_global,
329 ARRAY_SIZE(ctxsave_regs_3d_global));
330
331 /* read from set 0, write cmds through set0, restore to set0 */
332 if (register_sets == 2)
333 switch_gpu(&info, 0, 1, 1);
334
335 /* save set 0 specific regs */
336 setup_save_regs(&info,
337 ctxsave_regs_3d_perset,
338 ARRAY_SIZE(ctxsave_regs_3d_perset));
339
340 if (register_sets == 2) {
341 /* read from set1, write cmds through set1, restore to set1 */
342 switch_gpu(&info, 1, 2, 2);
343 /* note offset at which set 1 restore starts */
344 restore_set1_offset = info.restore_count;
345 /* save set 1 specific regs */
346 setup_save_regs(&info,
347 ctxsave_regs_3d_perset,
348 ARRAY_SIZE(ctxsave_regs_3d_perset));
349 }
350
351 /* read from set0, write cmds through set1, restore to set0 and 1 */
352 if (register_sets == 2)
353 switch_gpu(&info, 0, 2, 3);
354
355 if (info.ptr) {
356 save_end_v1(p, info.ptr);
357 info.ptr += SAVE_END_V1_SIZE;
358 }
359
360 wmb();
361
362 p->save_size = info.save_count + save_end_size;
363 p->restore_size = info.restore_count + RESTORE_END_SIZE;
364 p->save_incrs = info.save_incrs;
365 p->save_thresh = p->save_incrs - SAVE_THRESH_OFFSET;
366 p->restore_incrs = info.restore_incrs;
367}
368
369
370/*** ctx3d ***/
371
372static struct nvhost_hwctx *ctx3d_alloc_v1(struct nvhost_hwctx_handler *h,
373 struct nvhost_channel *ch)
374{
375 struct host1x_hwctx_handler *p = to_host1x_hwctx_handler(h);
376 struct host1x_hwctx *ctx = nvhost_3dctx_alloc_common(p, ch, false);
377
378 if (ctx)
379 return &ctx->hwctx;
380 else
381 return NULL;
382}
383
384struct nvhost_hwctx_handler *__init nvhost_gr3d_t30_ctxhandler_init(
385 u32 syncpt, u32 waitbase,
386 struct nvhost_channel *ch)
387{
388 struct nvmap_client *nvmap;
389 u32 *save_ptr;
390 struct host1x_hwctx_handler *p;
391
392 p = kmalloc(sizeof(*p), GFP_KERNEL);
393 if (!p)
394 return NULL;
395
396 nvmap = nvhost_get_host(ch->dev)->nvmap;
397
398 register_sets = tegra_gpu_register_sets();
399 BUG_ON(register_sets == 0 || register_sets > 2);
400
401 p->syncpt = syncpt;
402 p->waitbase = waitbase;
403
404 setup_save(p, NULL);
405
406 p->save_buf = nvmap_alloc(nvmap, p->save_size * 4, 32,
407 NVMAP_HANDLE_WRITE_COMBINE, 0);
408 if (IS_ERR(p->save_buf)) {
409 p->save_buf = NULL;
410 return NULL;
411 }
412
413 p->save_slots = 6;
414 if (register_sets == 2)
415 p->save_slots += 2;
416
417 save_ptr = nvmap_mmap(p->save_buf);
418 if (!save_ptr) {
419 nvmap_free(nvmap, p->save_buf);
420 p->save_buf = NULL;
421 return NULL;
422 }
423
424 p->save_phys = nvmap_pin(nvmap, p->save_buf);
425
426 setup_save(p, save_ptr);
427
428 p->h.alloc = ctx3d_alloc_v1;
429 p->h.save_push = save_push_v1;
430 p->h.save_service = NULL;
431 p->h.get = nvhost_3dctx_get;
432 p->h.put = nvhost_3dctx_put;
433
434 return &p->h;
435}