video: tegra: host: Register devices in SoC files
[linux-2.6.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-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 "nvhost_channel.h"
23 #include "host1x/host1x.h"
24 #include "host1x/host1x_channel.h"
25 #include "host1x/host1x_hardware.h"
26 #include "host1x/host1x_syncpt.h"
27 #include "gr3d.h"
28 #include "chip_support.h"
29 #include "nvhost_memmgr.h"
30
31 #include <linux/slab.h>
32
33 static const struct hwctx_reginfo ctxsave_regs_3d_global[] = {
34         HWCTX_REGINFO(0xe00,    4, DIRECT),
35         HWCTX_REGINFO(0xe05,   30, DIRECT),
36         HWCTX_REGINFO(0xe25,    2, DIRECT),
37         HWCTX_REGINFO(0xe28,    2, DIRECT),
38         HWCTX_REGINFO(0x001,    2, DIRECT),
39         HWCTX_REGINFO(0x00c,   10, DIRECT),
40         HWCTX_REGINFO(0x100,   34, DIRECT),
41         HWCTX_REGINFO(0x124,    2, DIRECT),
42         HWCTX_REGINFO(0x200,    5, DIRECT),
43         HWCTX_REGINFO(0x205, 1024, INDIRECT),
44         HWCTX_REGINFO(0x207, 1024, INDIRECT),
45         HWCTX_REGINFO(0x209,    1, DIRECT),
46         HWCTX_REGINFO(0x300,   64, DIRECT),
47         HWCTX_REGINFO(0x343,   25, DIRECT),
48         HWCTX_REGINFO(0x363,    2, DIRECT),
49         HWCTX_REGINFO(0x400,   16, DIRECT),
50         HWCTX_REGINFO(0x411,    1, DIRECT),
51         HWCTX_REGINFO(0x500,    4, DIRECT),
52         HWCTX_REGINFO(0x520,   32, DIRECT),
53         HWCTX_REGINFO(0x540,   64, INDIRECT),
54         HWCTX_REGINFO(0x600,   16, INDIRECT_4X),
55         HWCTX_REGINFO(0x603,  128, INDIRECT),
56         HWCTX_REGINFO(0x608,    4, DIRECT),
57         HWCTX_REGINFO(0x60e,    1, DIRECT),
58         HWCTX_REGINFO(0x700,   64, INDIRECT),
59         HWCTX_REGINFO(0x710,   50, DIRECT),
60         HWCTX_REGINFO(0x800,   16, INDIRECT_4X),
61         HWCTX_REGINFO(0x803,  512, INDIRECT),
62         HWCTX_REGINFO(0x805,   64, INDIRECT),
63         HWCTX_REGINFO(0x820,   32, DIRECT),
64         HWCTX_REGINFO(0x900,   64, INDIRECT),
65         HWCTX_REGINFO(0x902,    2, DIRECT),
66         HWCTX_REGINFO(0xa02,   10, DIRECT),
67         HWCTX_REGINFO(0xe04,    1, DIRECT),
68         HWCTX_REGINFO(0xe2a,    1, DIRECT),
69 };
70
71 /* the same context save command sequence is used for all contexts. */
72 #define SAVE_BEGIN_V0_SIZE 5
73 #define SAVE_DIRECT_V0_SIZE 3
74 #define SAVE_INDIRECT_V0_SIZE 5
75 #define SAVE_END_V0_SIZE 5
76 #define SAVE_INCRS 3
77 #define SAVE_THRESH_OFFSET 1
78 #define RESTORE_BEGIN_SIZE 4
79 #define RESTORE_DIRECT_SIZE 1
80 #define RESTORE_INDIRECT_SIZE 2
81 #define RESTORE_END_SIZE 1
82
83 struct save_info {
84         u32 *ptr;
85         unsigned int save_count;
86         unsigned int restore_count;
87         unsigned int save_incrs;
88         unsigned int restore_incrs;
89 };
90
91 static u32 *setup_restore_regs_v0(u32 *ptr,
92                         const struct hwctx_reginfo *regs,
93                         unsigned int nr_regs)
94 {
95         const struct hwctx_reginfo *rend = regs + nr_regs;
96
97         for ( ; regs != rend; ++regs) {
98                 u32 offset = regs->offset;
99                 u32 count = regs->count;
100                 u32 indoff = offset + 1;
101                 switch (regs->type) {
102                 case HWCTX_REGINFO_DIRECT:
103                         nvhost_3dctx_restore_direct(ptr, offset, count);
104                         ptr += RESTORE_DIRECT_SIZE;
105                         break;
106                 case HWCTX_REGINFO_INDIRECT_4X:
107                         ++indoff;
108                         /* fall through */
109                 case HWCTX_REGINFO_INDIRECT:
110                         nvhost_3dctx_restore_indirect(ptr,
111                                         offset, 0, indoff, count);
112                         ptr += RESTORE_INDIRECT_SIZE;
113                         break;
114                 }
115                 ptr += count;
116         }
117         return ptr;
118 }
119
120 static void setup_restore_v0(struct host1x_hwctx_handler *h, u32 *ptr)
121 {
122         nvhost_3dctx_restore_begin(h, ptr);
123         ptr += RESTORE_BEGIN_SIZE;
124
125         ptr = setup_restore_regs_v0(ptr,
126                         ctxsave_regs_3d_global,
127                         ARRAY_SIZE(ctxsave_regs_3d_global));
128
129         nvhost_3dctx_restore_end(h, ptr);
130
131         wmb();
132 }
133
134 /*** v0 saver ***/
135
136 static void save_push_v0(struct nvhost_hwctx *nctx, struct nvhost_cdma *cdma)
137 {
138         struct host1x_hwctx *ctx = to_host1x_hwctx(nctx);
139         struct host1x_hwctx_handler *p = host1x_hwctx_handler(ctx);
140
141         nvhost_cdma_push_gather(cdma,
142                         nvhost_get_host(nctx->channel->dev)->memmgr,
143                         p->save_buf,
144                         0,
145                         nvhost_opcode_gather(p->save_size),
146                         p->save_phys);
147 }
148
149 static void __init save_begin_v0(struct host1x_hwctx_handler *h, u32 *ptr)
150 {
151         /* 3d: when done, increment syncpt to base+1 */
152         ptr[0] = nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0);
153         ptr[1] = nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_OP_DONE,
154                         h->syncpt); /*  incr 1 */
155         /* host: wait for syncpt base+1 */
156         ptr[2] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
157                                         NV_CLASS_HOST_WAIT_SYNCPT_BASE, 1);
158         ptr[3] = nvhost_class_host_wait_syncpt_base(h->syncpt,
159                                                 h->waitbase, 1);
160         /* host: signal context read thread to start reading */
161         ptr[4] = nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_IMMEDIATE,
162                         h->syncpt); /* incr 2 */
163 }
164
165 static void __init save_direct_v0(u32 *ptr, u32 start_reg, u32 count)
166 {
167         ptr[0] = nvhost_opcode_nonincr(NV_CLASS_HOST_INDOFF, 1);
168         ptr[1] = nvhost_class_host_indoff_reg_read(NV_HOST_MODULE_GR3D,
169                                                 start_reg, true);
170         ptr[2] = nvhost_opcode_nonincr(NV_CLASS_HOST_INDDATA, count);
171 }
172
173 static void __init save_indirect_v0(u32 *ptr, u32 offset_reg, u32 offset,
174                         u32 data_reg, u32 count)
175 {
176         ptr[0] = nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID,
177                                         offset_reg, 1);
178         ptr[1] = offset;
179         ptr[2] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
180                                         NV_CLASS_HOST_INDOFF, 1);
181         ptr[3] = nvhost_class_host_indoff_reg_read(NV_HOST_MODULE_GR3D,
182                                                 data_reg, false);
183         ptr[4] = nvhost_opcode_nonincr(NV_CLASS_HOST_INDDATA, count);
184 }
185
186 static void __init save_end_v0(struct host1x_hwctx_handler *h, u32 *ptr)
187 {
188         /* Wait for context read service to finish (cpu incr 3) */
189         ptr[0] = nvhost_opcode_nonincr(NV_CLASS_HOST_WAIT_SYNCPT_BASE, 1);
190         ptr[1] = nvhost_class_host_wait_syncpt_base(h->syncpt,
191                         h->waitbase, h->save_incrs);
192         /* Advance syncpoint base */
193         ptr[2] = nvhost_opcode_nonincr(NV_CLASS_HOST_INCR_SYNCPT_BASE, 1);
194         ptr[3] = nvhost_class_host_incr_syncpt_base(NVWAITBASE_3D,
195                         h->save_incrs);
196         /* set class back to the unit */
197         ptr[4] = nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0);
198 }
199
200 static u32 *save_regs_v0(u32 *ptr, unsigned int *pending,
201                         void __iomem *chan_regs,
202                         const struct hwctx_reginfo *regs,
203                         unsigned int nr_regs)
204 {
205         const struct hwctx_reginfo *rend = regs + nr_regs;
206         int drain_result = 0;
207
208         for ( ; regs != rend; ++regs) {
209                 u32 count = regs->count;
210                 switch (regs->type) {
211                 case HWCTX_REGINFO_DIRECT:
212                         ptr += RESTORE_DIRECT_SIZE;
213                         break;
214                 case HWCTX_REGINFO_INDIRECT:
215                 case HWCTX_REGINFO_INDIRECT_4X:
216                         ptr += RESTORE_INDIRECT_SIZE;
217                         break;
218                 }
219                 drain_result = host1x_drain_read_fifo(chan_regs,
220                         ptr, count, pending);
221                 BUG_ON(drain_result < 0);
222                 ptr += count;
223         }
224         return ptr;
225 }
226
227 /*** save ***/
228
229 static void __init setup_save_regs(struct save_info *info,
230                         const struct hwctx_reginfo *regs,
231                         unsigned int nr_regs)
232 {
233         const struct hwctx_reginfo *rend = regs + nr_regs;
234         u32 *ptr = info->ptr;
235         unsigned int save_count = info->save_count;
236         unsigned int restore_count = info->restore_count;
237
238         for ( ; regs != rend; ++regs) {
239                 u32 offset = regs->offset;
240                 u32 count = regs->count;
241                 u32 indoff = offset + 1;
242                 switch (regs->type) {
243                 case HWCTX_REGINFO_DIRECT:
244                         if (ptr) {
245                                 save_direct_v0(ptr, offset, count);
246                                 ptr += SAVE_DIRECT_V0_SIZE;
247                         }
248                         save_count += SAVE_DIRECT_V0_SIZE;
249                         restore_count += RESTORE_DIRECT_SIZE;
250                         break;
251                 case HWCTX_REGINFO_INDIRECT_4X:
252                         ++indoff;
253                         /* fall through */
254                 case HWCTX_REGINFO_INDIRECT:
255                         if (ptr) {
256                                 save_indirect_v0(ptr, offset, 0,
257                                                 indoff, count);
258                                 ptr += SAVE_INDIRECT_V0_SIZE;
259                         }
260                         save_count += SAVE_INDIRECT_V0_SIZE;
261                         restore_count += RESTORE_INDIRECT_SIZE;
262                         break;
263                 }
264                 if (ptr) {
265                         /* SAVE cases only: reserve room for incoming data */
266                         u32 k = 0;
267                         /*
268                          * Create a signature pattern for indirect data (which
269                          * will be overwritten by true incoming data) for
270                          * better deducing where we are in a long command
271                          * sequence, when given only a FIFO snapshot for debug
272                          * purposes.
273                         */
274                         for (k = 0; k < count; k++)
275                                 *(ptr + k) = 0xd000d000 | (offset << 16) | k;
276                         ptr += count;
277                 }
278                 save_count += count;
279                 restore_count += count;
280         }
281
282         info->ptr = ptr;
283         info->save_count = save_count;
284         info->restore_count = restore_count;
285 }
286
287 static void __init setup_save(struct host1x_hwctx_handler *h, u32 *ptr)
288 {
289         struct save_info info = {
290                 ptr,
291                 SAVE_BEGIN_V0_SIZE,
292                 RESTORE_BEGIN_SIZE,
293                 SAVE_INCRS,
294                 1
295         };
296
297         if (info.ptr) {
298                 save_begin_v0(h, info.ptr);
299                 info.ptr += SAVE_BEGIN_V0_SIZE;
300         }
301
302         /* save regs */
303         setup_save_regs(&info,
304                         ctxsave_regs_3d_global,
305                         ARRAY_SIZE(ctxsave_regs_3d_global));
306
307         if (info.ptr) {
308                 save_end_v0(h, info.ptr);
309                 info.ptr += SAVE_END_V0_SIZE;
310         }
311
312         wmb();
313
314         h->save_size = info.save_count + SAVE_END_V0_SIZE;
315         h->restore_size = info.restore_count + RESTORE_END_SIZE;
316         h->save_incrs = info.save_incrs;
317         h->save_thresh = h->save_incrs - SAVE_THRESH_OFFSET;
318         h->restore_incrs = info.restore_incrs;
319 }
320
321
322
323 /*** ctx3d ***/
324
325 static struct nvhost_hwctx *ctx3d_alloc_v0(struct nvhost_hwctx_handler *h,
326                 struct nvhost_channel *ch)
327 {
328         struct host1x_hwctx_handler *p = to_host1x_hwctx_handler(h);
329         struct host1x_hwctx *ctx =
330                 nvhost_3dctx_alloc_common(p, ch, true);
331         if (ctx) {
332                 setup_restore_v0(p, ctx->restore_virt);
333                 return &ctx->hwctx;
334         } else
335                 return NULL;
336 }
337
338 static void ctx3d_save_service(struct nvhost_hwctx *nctx)
339 {
340         struct host1x_hwctx *ctx = to_host1x_hwctx(nctx);
341
342         u32 *ptr = (u32 *)ctx->restore_virt + RESTORE_BEGIN_SIZE;
343         unsigned int pending = 0;
344
345         ptr = save_regs_v0(ptr, &pending, nctx->channel->aperture,
346                         ctxsave_regs_3d_global,
347                         ARRAY_SIZE(ctxsave_regs_3d_global));
348
349         wmb();
350         nvhost_syncpt_cpu_incr(&nvhost_get_host(nctx->channel->dev)->syncpt,
351                         host1x_hwctx_handler(ctx)->syncpt);
352 }
353
354 struct nvhost_hwctx_handler *nvhost_gr3d_t20_ctxhandler_init(
355                 u32 syncpt, u32 waitbase,
356                 struct nvhost_channel *ch)
357 {
358         struct mem_mgr *memmgr;
359         u32 *save_ptr;
360         struct host1x_hwctx_handler *p;
361
362         p = kmalloc(sizeof(*p), GFP_KERNEL);
363         if (!p)
364                 return NULL;
365         memmgr = nvhost_get_host(ch->dev)->memmgr;
366
367         p->syncpt = syncpt;
368         p->waitbase = waitbase;
369
370         setup_save(p, NULL);
371
372         p->save_buf = mem_op().alloc(memmgr, p->save_size * sizeof(u32), 32,
373                                 mem_mgr_flag_write_combine);
374         if (IS_ERR(p->save_buf)) {
375                 p->save_buf = NULL;
376                 return NULL;
377         }
378
379         p->save_slots = 1;
380
381         save_ptr = mem_op().mmap(p->save_buf);
382         if (!save_ptr) {
383                 mem_op().put(memmgr, p->save_buf);
384                 p->save_buf = NULL;
385                 return NULL;
386         }
387
388         p->save_phys = mem_op().pin(memmgr, p->save_buf);
389
390         setup_save(p, save_ptr);
391
392         p->h.alloc = ctx3d_alloc_v0;
393         p->h.save_push = save_push_v0;
394         p->h.save_service = ctx3d_save_service;
395         p->h.get = nvhost_3dctx_get;
396         p->h.put = nvhost_3dctx_put;
397
398         return &p->h;
399 }