9c39acdf4f62e51fc1c813285a34134b2d21e670
[linux-3.10.git] / drivers / video / tegra / host / gr3d / gr3d_t20.c
1 /*
2  * drivers/video/tegra/host/gr3d/gr3d_t20.c
3  *
4  * Tegra Graphics Host 3D for Tegra2
5  *
6  * Copyright (c) 2010-2013, 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 "nvhost_channel.h"
23 #include "host1x/host1x.h"
24 #include "host1x/host1x01_hardware.h"
25 #include "gr3d.h"
26 #include "chip_support.h"
27 #include "nvhost_memmgr.h"
28 #include "nvhost_job.h"
29 #include "nvhost_acm.h"
30 #include "class_ids.h"
31
32 #include <linux/slab.h>
33 #include <linux/scatterlist.h>
34
35 static const struct hwctx_reginfo ctxsave_regs_3d_global[] = {
36         HWCTX_REGINFO(0xe00,    4, DIRECT),
37         HWCTX_REGINFO(0xe05,   30, DIRECT),
38         HWCTX_REGINFO(0xe25,    2, DIRECT),
39         HWCTX_REGINFO(0xe28,    2, 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(0x500,    4, DIRECT),
54         HWCTX_REGINFO(0x520,   32, DIRECT),
55         HWCTX_REGINFO(0x540,   64, INDIRECT),
56         HWCTX_REGINFO(0x600,   16, INDIRECT_4X),
57         HWCTX_REGINFO(0x603,  128, INDIRECT),
58         HWCTX_REGINFO(0x608,    4, DIRECT),
59         HWCTX_REGINFO(0x60e,    1, DIRECT),
60         HWCTX_REGINFO(0x700,   64, INDIRECT),
61         HWCTX_REGINFO(0x710,   50, DIRECT),
62         HWCTX_REGINFO(0x800,   16, INDIRECT_4X),
63         HWCTX_REGINFO(0x803,  512, INDIRECT),
64         HWCTX_REGINFO(0x805,   64, INDIRECT),
65         HWCTX_REGINFO(0x820,   32, DIRECT),
66         HWCTX_REGINFO(0x900,   64, INDIRECT),
67         HWCTX_REGINFO(0x902,    2, DIRECT),
68         HWCTX_REGINFO(0xa02,   10, DIRECT),
69         HWCTX_REGINFO(0xe04,    1, DIRECT),
70         HWCTX_REGINFO(0xe2a,    1, DIRECT),
71 };
72
73 /* the same context save command sequence is used for all contexts. */
74 #define SAVE_BEGIN_V0_SIZE 5
75 #define SAVE_DIRECT_V0_SIZE 3
76 #define SAVE_INDIRECT_V0_SIZE 5
77 #define SAVE_END_V0_SIZE 5
78 #define SAVE_INCRS 3
79 #define SAVE_THRESH_OFFSET 1
80 #define RESTORE_BEGIN_SIZE 4
81 #define RESTORE_DIRECT_SIZE 1
82 #define RESTORE_INDIRECT_SIZE 2
83 #define RESTORE_END_SIZE 1
84
85 struct save_info {
86         u32 *ptr;
87         unsigned int save_count;
88         unsigned int restore_count;
89         unsigned int save_incrs;
90         unsigned int restore_incrs;
91 };
92
93 static u32 *setup_restore_regs_v0(u32 *ptr,
94                         const struct hwctx_reginfo *regs,
95                         unsigned int nr_regs)
96 {
97         const struct hwctx_reginfo *rend = regs + nr_regs;
98
99         for ( ; regs != rend; ++regs) {
100                 u32 offset = regs->offset;
101                 u32 count = regs->count;
102                 u32 indoff = offset + 1;
103                 switch (regs->type) {
104                 case HWCTX_REGINFO_DIRECT:
105                         nvhost_3dctx_restore_direct(ptr, offset, count);
106                         ptr += RESTORE_DIRECT_SIZE;
107                         break;
108                 case HWCTX_REGINFO_INDIRECT_4X:
109                         ++indoff;
110                         /* fall through */
111                 case HWCTX_REGINFO_INDIRECT:
112                         nvhost_3dctx_restore_indirect(ptr,
113                                         offset, 0, indoff, count);
114                         ptr += RESTORE_INDIRECT_SIZE;
115                         break;
116                 }
117                 ptr += count;
118         }
119         return ptr;
120 }
121
122 static void setup_restore_v0(struct host1x_hwctx_handler *h, u32 *ptr)
123 {
124         nvhost_3dctx_restore_begin(h, ptr);
125         ptr += RESTORE_BEGIN_SIZE;
126
127         ptr = setup_restore_regs_v0(ptr,
128                         ctxsave_regs_3d_global,
129                         ARRAY_SIZE(ctxsave_regs_3d_global));
130
131         nvhost_3dctx_restore_end(h, ptr);
132
133         wmb();
134 }
135
136 /*** v0 saver ***/
137
138 static void save_push_v0(struct nvhost_hwctx *nctx, struct nvhost_cdma *cdma)
139 {
140         struct host1x_hwctx *ctx = to_host1x_hwctx(nctx);
141         struct host1x_hwctx_handler *p = host1x_hwctx_handler(ctx);
142
143         nvhost_cdma_push_gather(cdma,
144                         nvhost_get_host(nctx->channel->dev)->memmgr,
145                         p->save_buf,
146                         0,
147                         nvhost_opcode_gather(p->save_size),
148                         p->save_phys);
149 }
150
151 static void save_begin_v0(struct host1x_hwctx_handler *h, u32 *ptr)
152 {
153         /* 3d: when done, increment syncpt to base+1 */
154         ptr[0] = nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0);
155         ptr[1] = nvhost_opcode_imm_incr_syncpt(
156                         host1x_uclass_incr_syncpt_cond_op_done_v(),
157                         h->h.syncpt); /*  incr 1 */
158         /* host: wait for syncpt base+1 */
159         ptr[2] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
160                                         host1x_uclass_wait_syncpt_base_r(), 1);
161         ptr[3] = nvhost_class_host_wait_syncpt_base(h->h.syncpt,
162                                                 h->h.waitbase, 1);
163         /* host: signal context read thread to start reading */
164         ptr[4] = nvhost_opcode_imm_incr_syncpt(
165                         host1x_uclass_incr_syncpt_cond_immediate_v(),
166                         h->h.syncpt); /* incr 2 */
167 }
168
169 static void save_direct_v0(u32 *ptr, u32 start_reg, u32 count)
170 {
171         ptr[0] = nvhost_opcode_nonincr(host1x_uclass_indoff_r(), 1);
172         ptr[1] = nvhost_class_host_indoff_reg_read(
173                         host1x_uclass_indoff_indmodid_gr3d_v(),
174                         start_reg, true);
175         ptr[2] = nvhost_opcode_nonincr(host1x_uclass_inddata_r(), count);
176 }
177
178 static void save_indirect_v0(u32 *ptr, u32 offset_reg, u32 offset,
179                         u32 data_reg, u32 count)
180 {
181         ptr[0] = nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID,
182                                         offset_reg, 1);
183         ptr[1] = offset;
184         ptr[2] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
185                                         host1x_uclass_indoff_r(), 1);
186         ptr[3] = nvhost_class_host_indoff_reg_read(
187                         host1x_uclass_indoff_indmodid_gr3d_v(),
188                         data_reg, false);
189         ptr[4] = nvhost_opcode_nonincr(host1x_uclass_inddata_r(), count);
190 }
191
192 static void save_end_v0(struct host1x_hwctx_handler *h, u32 *ptr)
193 {
194         /* Wait for context read service to finish (cpu incr 3) */
195         ptr[0] = nvhost_opcode_nonincr(host1x_uclass_wait_syncpt_base_r(), 1);
196         ptr[1] = nvhost_class_host_wait_syncpt_base(h->h.syncpt,
197                         h->h.waitbase, h->save_incrs);
198         /* Advance syncpoint base */
199         ptr[2] = nvhost_opcode_nonincr(host1x_uclass_incr_syncpt_base_r(), 1);
200         ptr[3] = nvhost_class_host_incr_syncpt_base(h->h.waitbase,
201                         h->save_incrs);
202         /* set class back to the unit */
203         ptr[4] = nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0);
204 }
205
206 static u32 *save_regs_v0(u32 *ptr, unsigned int *pending,
207                         struct nvhost_channel *ch,
208                         const struct hwctx_reginfo *regs,
209                         unsigned int nr_regs)
210 {
211         const struct hwctx_reginfo *rend = regs + nr_regs;
212         int drain_result = 0;
213
214         for ( ; regs != rend; ++regs) {
215                 u32 count = regs->count;
216                 switch (regs->type) {
217                 case HWCTX_REGINFO_DIRECT:
218                         ptr += RESTORE_DIRECT_SIZE;
219                         break;
220                 case HWCTX_REGINFO_INDIRECT:
221                 case HWCTX_REGINFO_INDIRECT_4X:
222                         ptr += RESTORE_INDIRECT_SIZE;
223                         break;
224                 }
225                 drain_result = nvhost_channel_drain_read_fifo(ch,
226                         ptr, count, pending);
227                 WARN_ON(drain_result < 0);
228                 ptr += count;
229         }
230         return ptr;
231 }
232
233 /*** save ***/
234
235 static void setup_save_regs(struct save_info *info,
236                         const struct hwctx_reginfo *regs,
237                         unsigned int nr_regs)
238 {
239         const struct hwctx_reginfo *rend = regs + nr_regs;
240         u32 *ptr = info->ptr;
241         unsigned int save_count = info->save_count;
242         unsigned int restore_count = info->restore_count;
243
244         for ( ; regs != rend; ++regs) {
245                 u32 offset = regs->offset;
246                 u32 count = regs->count;
247                 u32 indoff = offset + 1;
248                 switch (regs->type) {
249                 case HWCTX_REGINFO_DIRECT:
250                         if (ptr) {
251                                 save_direct_v0(ptr, offset, count);
252                                 ptr += SAVE_DIRECT_V0_SIZE;
253                         }
254                         save_count += SAVE_DIRECT_V0_SIZE;
255                         restore_count += RESTORE_DIRECT_SIZE;
256                         break;
257                 case HWCTX_REGINFO_INDIRECT_4X:
258                         ++indoff;
259                         /* fall through */
260                 case HWCTX_REGINFO_INDIRECT:
261                         if (ptr) {
262                                 save_indirect_v0(ptr, offset, 0,
263                                                 indoff, count);
264                                 ptr += SAVE_INDIRECT_V0_SIZE;
265                         }
266                         save_count += SAVE_INDIRECT_V0_SIZE;
267                         restore_count += RESTORE_INDIRECT_SIZE;
268                         break;
269                 }
270                 if (ptr) {
271                         /* SAVE cases only: reserve room for incoming data */
272                         u32 k = 0;
273                         /*
274                          * Create a signature pattern for indirect data (which
275                          * will be overwritten by true incoming data) for
276                          * better deducing where we are in a long command
277                          * sequence, when given only a FIFO snapshot for debug
278                          * purposes.
279                         */
280                         for (k = 0; k < count; k++)
281                                 *(ptr + k) = 0xd000d000 | (offset << 16) | k;
282                         ptr += count;
283                 }
284                 save_count += count;
285                 restore_count += count;
286         }
287
288         info->ptr = ptr;
289         info->save_count = save_count;
290         info->restore_count = restore_count;
291 }
292
293 static void setup_save(struct host1x_hwctx_handler *h, u32 *ptr)
294 {
295         struct save_info info = {
296                 ptr,
297                 SAVE_BEGIN_V0_SIZE,
298                 RESTORE_BEGIN_SIZE,
299                 SAVE_INCRS,
300                 1
301         };
302
303         if (info.ptr) {
304                 save_begin_v0(h, info.ptr);
305                 info.ptr += SAVE_BEGIN_V0_SIZE;
306         }
307
308         /* save regs */
309         setup_save_regs(&info,
310                         ctxsave_regs_3d_global,
311                         ARRAY_SIZE(ctxsave_regs_3d_global));
312
313         if (info.ptr) {
314                 save_end_v0(h, info.ptr);
315                 info.ptr += SAVE_END_V0_SIZE;
316         }
317
318         wmb();
319
320         h->save_size = info.save_count + SAVE_END_V0_SIZE;
321         h->restore_size = info.restore_count + RESTORE_END_SIZE;
322         h->save_incrs = info.save_incrs;
323         h->h.save_thresh = h->save_incrs - SAVE_THRESH_OFFSET;
324         h->restore_incrs = info.restore_incrs;
325 }
326
327
328
329 /*** ctx3d ***/
330
331 static struct nvhost_hwctx *ctx3d_alloc_v0(struct nvhost_hwctx_handler *h,
332                 struct nvhost_channel *ch)
333 {
334         struct host1x_hwctx_handler *p = to_host1x_hwctx_handler(h);
335         struct host1x_hwctx *ctx =
336                 nvhost_3dctx_alloc_common(p, ch, true);
337         if (ctx) {
338                 setup_restore_v0(p, ctx->restore_virt);
339                 return &ctx->hwctx;
340         } else
341                 return NULL;
342 }
343
344 static void ctx3d_save_service(struct nvhost_hwctx *nctx)
345 {
346         struct host1x_hwctx *ctx = to_host1x_hwctx(nctx);
347
348         u32 *ptr = (u32 *)ctx->restore_virt + RESTORE_BEGIN_SIZE;
349         unsigned int pending = 0;
350
351         ptr = save_regs_v0(ptr, &pending, nctx->channel,
352                         ctxsave_regs_3d_global,
353                         ARRAY_SIZE(ctxsave_regs_3d_global));
354
355         wmb();
356         nvhost_syncpt_cpu_incr(&nvhost_get_host(nctx->channel->dev)->syncpt,
357                         ctx->hwctx.h->syncpt);
358 }
359
360 struct nvhost_hwctx_handler *nvhost_gr3d_t20_ctxhandler_init(
361                 u32 syncpt, u32 waitbase,
362                 struct nvhost_channel *ch)
363 {
364         struct mem_mgr *memmgr;
365         u32 *save_ptr;
366         struct host1x_hwctx_handler *p;
367
368         p = kmalloc(sizeof(*p), GFP_KERNEL);
369         if (!p)
370                 return NULL;
371         memmgr = nvhost_get_host(ch->dev)->memmgr;
372
373         p->h.syncpt = syncpt;
374         p->h.waitbase = waitbase;
375
376         setup_save(p, NULL);
377
378         p->save_buf = nvhost_memmgr_alloc(memmgr,
379                         p->save_size * sizeof(u32), 32,
380                         mem_mgr_flag_write_combine);
381         if (IS_ERR(p->save_buf))
382                 goto fail_alloc;
383
384         save_ptr = nvhost_memmgr_mmap(p->save_buf);
385         if (!save_ptr)
386                 goto fail_mmap;
387
388         p->save_sgt = nvhost_memmgr_pin(memmgr, p->save_buf);
389         if (IS_ERR(p->save_sgt))
390                 goto fail_pin;
391         p->save_phys = sg_dma_address(p->save_sgt->sgl);
392
393         setup_save(p, save_ptr);
394
395         nvhost_memmgr_munmap(p->save_buf, save_ptr);
396
397         p->save_slots = 1;
398         p->h.alloc = ctx3d_alloc_v0;
399         p->h.save_push = save_push_v0;
400         p->h.restore_push = nvhost_3dctx_restore_push;
401         p->h.save_service = ctx3d_save_service;
402         p->h.get = nvhost_3dctx_get;
403         p->h.put = nvhost_3dctx_put;
404
405         return &p->h;
406
407 fail_pin:
408         nvhost_memmgr_munmap(p->save_buf, save_ptr);
409 fail_mmap:
410         nvhost_memmgr_put(memmgr, p->save_buf);
411 fail_alloc:
412         kfree(p);
413         return NULL;
414 }
415
416 int nvhost_gr3d_t20_read_reg(struct platform_device *dev,
417         struct nvhost_channel *channel,
418         struct nvhost_hwctx *hwctx,
419         u32 offset,
420         u32 *value)
421 {
422         struct host1x_hwctx_handler *h = to_host1x_hwctx_handler(hwctx->h);
423         u32 syncpt_incrs = 4;
424         unsigned int pending = 0;
425         DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
426         void *ref;
427         void *read_waiter = NULL;
428         struct nvhost_job *job;
429         int err;
430         struct mem_handle *mem = NULL;
431         u32 *cmdbuf_ptr = NULL;
432         struct mem_mgr *memmgr = hwctx->memmgr;
433         u32 opcodes[] = {
434                 /* Switch to 3D - wait for it to complete what it was doing */
435                 nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0),
436                 nvhost_opcode_imm_incr_syncpt(
437                                 host1x_uclass_incr_syncpt_cond_op_done_v(),
438                                 h->h.syncpt),
439                 nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
440                                 host1x_uclass_wait_syncpt_base_r(), 1),
441                 nvhost_class_host_wait_syncpt_base(h->h.syncpt,
442                                 h->h.waitbase, 1),
443                 /*  Tell 3D to send register value to FIFO */
444                 nvhost_opcode_nonincr(host1x_uclass_indoff_r(), 1),
445                 nvhost_class_host_indoff_reg_read(
446                                 host1x_uclass_indoff_indmodid_gr3d_v(),
447                                 offset, false),
448                 nvhost_opcode_imm(host1x_uclass_inddata_r(), 0),
449                 /*  Increment syncpt to indicate that FIFO can be read */
450                 nvhost_opcode_imm_incr_syncpt(
451                                 host1x_uclass_incr_syncpt_cond_immediate_v(),
452                                 h->h.syncpt),
453                 /*  Wait for value to be read from FIFO */
454                 nvhost_opcode_nonincr(host1x_uclass_wait_syncpt_base_r(), 1),
455                 nvhost_class_host_wait_syncpt_base(h->h.syncpt,
456                                 h->h.waitbase, 3),
457                 /*  Indicate submit complete */
458                 nvhost_opcode_nonincr(host1x_uclass_incr_syncpt_base_r(), 1),
459                 nvhost_class_host_incr_syncpt_base(h->h.waitbase, 4),
460                 nvhost_opcode_imm_incr_syncpt(
461                                 host1x_uclass_incr_syncpt_cond_immediate_v(),
462                                 h->h.syncpt),
463         };
464
465         mem = nvhost_memmgr_alloc(memmgr, sizeof(opcodes),
466                         32, mem_mgr_flag_uncacheable);
467         if (IS_ERR(mem))
468                 return PTR_ERR(mem);
469
470         cmdbuf_ptr = nvhost_memmgr_mmap(mem);
471         if (!cmdbuf_ptr) {
472                 err = -ENOMEM;
473                 goto done;
474         }
475
476         read_waiter = nvhost_intr_alloc_waiter();
477         if (!read_waiter) {
478                 err = -ENOMEM;
479                 goto done;
480         }
481
482         job = nvhost_job_alloc(channel, hwctx, 1, 0, 0, memmgr);
483         if (!job) {
484                 err = -ENOMEM;
485                 goto done;
486         }
487
488         job->syncpt_id = h->h.syncpt;
489         job->syncpt_incrs = syncpt_incrs;
490         job->serialize = 1;
491         memcpy(cmdbuf_ptr, opcodes, sizeof(opcodes));
492
493         /* Submit job */
494         nvhost_job_add_gather(job, nvhost_memmgr_handle_to_id(mem),
495                         ARRAY_SIZE(opcodes), 0);
496
497         err = nvhost_job_pin(job, &nvhost_get_host(dev)->syncpt);
498         if (err)
499                 goto done;
500
501         err = nvhost_channel_submit(job);
502         if (err)
503                 goto done;
504
505         /* Wait for FIFO to be ready */
506         err = nvhost_intr_add_action(&nvhost_get_host(dev)->intr,
507                         h->h.syncpt, job->syncpt_end - 2,
508                         NVHOST_INTR_ACTION_WAKEUP, &wq,
509                         read_waiter,
510                         &ref);
511         read_waiter = NULL;
512         WARN(err, "Failed to set wakeup interrupt");
513         wait_event(wq,
514                 nvhost_syncpt_is_expired(&nvhost_get_host(dev)->syncpt,
515                                 h->h.syncpt, job->syncpt_end - 2));
516         nvhost_intr_put_ref(&nvhost_get_host(dev)->intr, h->h.syncpt,
517                         ref);
518
519         /* Read the register value from FIFO */
520         err = nvhost_channel_drain_read_fifo(channel, value, 1, &pending);
521
522         /* Indicate we've read the value */
523         nvhost_syncpt_cpu_incr(&nvhost_get_host(dev)->syncpt,
524                         h->h.syncpt);
525
526         nvhost_job_put(job);
527         job = NULL;
528
529 done:
530         kfree(read_waiter);
531         if (cmdbuf_ptr)
532                 nvhost_memmgr_munmap(mem, cmdbuf_ptr);
533         if (mem)
534                 nvhost_memmgr_put(memmgr, mem);
535         return err;
536 }
537