aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/tegra/host/mpe/mpe.c
diff options
context:
space:
mode:
authorJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
committerJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
commitfcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch)
treea57612d1888735a2ec7972891b68c1ac5ec8faea /drivers/video/tegra/host/mpe/mpe.c
parent8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff)
Added missing tegra files.HEADmaster
Diffstat (limited to 'drivers/video/tegra/host/mpe/mpe.c')
-rw-r--r--drivers/video/tegra/host/mpe/mpe.c638
1 files changed, 638 insertions, 0 deletions
diff --git a/drivers/video/tegra/host/mpe/mpe.c b/drivers/video/tegra/host/mpe/mpe.c
new file mode 100644
index 00000000000..28002aa637a
--- /dev/null
+++ b/drivers/video/tegra/host/mpe/mpe.c
@@ -0,0 +1,638 @@
1/*
2 * drivers/video/tegra/host/mpe/mpe.c
3 *
4 * Tegra Graphics Host MPE
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 "dev.h"
23#include "host1x/host1x_hardware.h"
24#include "host1x/host1x_channel.h"
25#include "host1x/host1x_syncpt.h"
26#include "host1x/host1x_hwctx.h"
27#include "t20/t20.h"
28#include <linux/slab.h>
29#include "bus_client.h"
30
31enum {
32 HWCTX_REGINFO_NORMAL = 0,
33 HWCTX_REGINFO_STASH,
34 HWCTX_REGINFO_CALCULATE,
35 HWCTX_REGINFO_WRITEBACK
36};
37
38const struct hwctx_reginfo ctxsave_regs_mpe[] = {
39 HWCTX_REGINFO(0x124, 1, STASH),
40 HWCTX_REGINFO(0x123, 1, STASH),
41 HWCTX_REGINFO(0x103, 1, STASH),
42 HWCTX_REGINFO(0x074, 1, STASH),
43 HWCTX_REGINFO(0x021, 1, NORMAL),
44 HWCTX_REGINFO(0x020, 1, STASH),
45 HWCTX_REGINFO(0x024, 2, NORMAL),
46 HWCTX_REGINFO(0x0e6, 1, NORMAL),
47 HWCTX_REGINFO(0x3fc, 1, NORMAL),
48 HWCTX_REGINFO(0x3d0, 1, NORMAL),
49 HWCTX_REGINFO(0x3d4, 1, NORMAL),
50 HWCTX_REGINFO(0x013, 1, NORMAL),
51 HWCTX_REGINFO(0x022, 1, NORMAL),
52 HWCTX_REGINFO(0x030, 4, NORMAL),
53 HWCTX_REGINFO(0x023, 1, NORMAL),
54 HWCTX_REGINFO(0x070, 1, NORMAL),
55 HWCTX_REGINFO(0x0a0, 9, NORMAL),
56 HWCTX_REGINFO(0x071, 1, NORMAL),
57 HWCTX_REGINFO(0x100, 4, NORMAL),
58 HWCTX_REGINFO(0x104, 2, NORMAL),
59 HWCTX_REGINFO(0x108, 9, NORMAL),
60 HWCTX_REGINFO(0x112, 2, NORMAL),
61 HWCTX_REGINFO(0x114, 1, STASH),
62 HWCTX_REGINFO(0x014, 1, NORMAL),
63 HWCTX_REGINFO(0x072, 1, NORMAL),
64 HWCTX_REGINFO(0x200, 1, NORMAL),
65 HWCTX_REGINFO(0x0d1, 1, NORMAL),
66 HWCTX_REGINFO(0x0d0, 1, NORMAL),
67 HWCTX_REGINFO(0x0c0, 1, NORMAL),
68 HWCTX_REGINFO(0x0c3, 2, NORMAL),
69 HWCTX_REGINFO(0x0d2, 1, NORMAL),
70 HWCTX_REGINFO(0x0d8, 1, NORMAL),
71 HWCTX_REGINFO(0x0e0, 2, NORMAL),
72 HWCTX_REGINFO(0x07f, 2, NORMAL),
73 HWCTX_REGINFO(0x084, 8, NORMAL),
74 HWCTX_REGINFO(0x0d3, 1, NORMAL),
75 HWCTX_REGINFO(0x040, 13, NORMAL),
76 HWCTX_REGINFO(0x050, 6, NORMAL),
77 HWCTX_REGINFO(0x058, 1, NORMAL),
78 HWCTX_REGINFO(0x057, 1, NORMAL),
79 HWCTX_REGINFO(0x111, 1, NORMAL),
80 HWCTX_REGINFO(0x130, 3, NORMAL),
81 HWCTX_REGINFO(0x201, 1, NORMAL),
82 HWCTX_REGINFO(0x068, 2, NORMAL),
83 HWCTX_REGINFO(0x08c, 1, NORMAL),
84 HWCTX_REGINFO(0x0cf, 1, NORMAL),
85 HWCTX_REGINFO(0x082, 2, NORMAL),
86 HWCTX_REGINFO(0x075, 1, NORMAL),
87 HWCTX_REGINFO(0x0e8, 1, NORMAL),
88 HWCTX_REGINFO(0x056, 1, NORMAL),
89 HWCTX_REGINFO(0x057, 1, NORMAL),
90 HWCTX_REGINFO(0x073, 1, CALCULATE),
91 HWCTX_REGINFO(0x074, 1, NORMAL),
92 HWCTX_REGINFO(0x075, 1, NORMAL),
93 HWCTX_REGINFO(0x076, 1, STASH),
94 HWCTX_REGINFO(0x11a, 9, NORMAL),
95 HWCTX_REGINFO(0x123, 1, NORMAL),
96 HWCTX_REGINFO(0x124, 1, NORMAL),
97 HWCTX_REGINFO(0x12a, 5, NORMAL),
98 HWCTX_REGINFO(0x12f, 1, STASH),
99 HWCTX_REGINFO(0x125, 2, NORMAL),
100 HWCTX_REGINFO(0x034, 1, NORMAL),
101 HWCTX_REGINFO(0x133, 2, NORMAL),
102 HWCTX_REGINFO(0x127, 1, NORMAL),
103 HWCTX_REGINFO(0x106, 1, WRITEBACK),
104 HWCTX_REGINFO(0x107, 1, WRITEBACK)
105};
106
107#define NR_STASHES 8
108#define NR_WRITEBACKS 2
109
110#define RC_RAM_LOAD_CMD 0x115
111#define RC_RAM_LOAD_DATA 0x116
112#define RC_RAM_READ_CMD 0x128
113#define RC_RAM_READ_DATA 0x129
114#define RC_RAM_SIZE 692
115
116#define IRFR_RAM_LOAD_CMD 0xc5
117#define IRFR_RAM_LOAD_DATA 0xc6
118#define IRFR_RAM_READ_CMD 0xcd
119#define IRFR_RAM_READ_DATA 0xce
120#define IRFR_RAM_SIZE 408
121
122struct mpe_save_info {
123 u32 in[NR_STASHES];
124 u32 out[NR_WRITEBACKS];
125 unsigned in_pos;
126 unsigned out_pos;
127 u32 h264_mode;
128};
129
130
131/*** restore ***/
132
133static unsigned int restore_size;
134
135static void restore_begin(struct host1x_hwctx_handler *h, u32 *ptr)
136{
137 /* set class to host */
138 ptr[0] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
139 NV_CLASS_HOST_INCR_SYNCPT_BASE, 1);
140 /* increment sync point base */
141 ptr[1] = nvhost_class_host_incr_syncpt_base(h->waitbase, 1);
142 /* set class to MPE */
143 ptr[2] = nvhost_opcode_setclass(NV_VIDEO_ENCODE_MPEG_CLASS_ID, 0, 0);
144}
145#define RESTORE_BEGIN_SIZE 3
146
147static void restore_ram(u32 *ptr, unsigned words,
148 unsigned cmd_reg, unsigned data_reg)
149{
150 ptr[0] = nvhost_opcode_imm(cmd_reg, words);
151 ptr[1] = nvhost_opcode_nonincr(data_reg, words);
152}
153#define RESTORE_RAM_SIZE 2
154
155static void restore_end(struct host1x_hwctx_handler *h, u32 *ptr)
156{
157 /* syncpt increment to track restore gather. */
158 ptr[0] = nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_OP_DONE,
159 h->syncpt);
160}
161#define RESTORE_END_SIZE 1
162
163static u32 *setup_restore_regs(u32 *ptr,
164 const struct hwctx_reginfo *regs,
165 unsigned int nr_regs)
166{
167 const struct hwctx_reginfo *rend = regs + nr_regs;
168
169 for ( ; regs != rend; ++regs) {
170 u32 offset = regs->offset;
171 u32 count = regs->count;
172 *ptr++ = nvhost_opcode_incr(offset, count);
173 ptr += count;
174 }
175 return ptr;
176}
177
178static u32 *setup_restore_ram(u32 *ptr, unsigned words,
179 unsigned cmd_reg, unsigned data_reg)
180{
181 restore_ram(ptr, words, cmd_reg, data_reg);
182 return ptr + (RESTORE_RAM_SIZE + words);
183}
184
185static void setup_restore(struct host1x_hwctx_handler *h, u32 *ptr)
186{
187 restore_begin(h, ptr);
188 ptr += RESTORE_BEGIN_SIZE;
189
190 ptr = setup_restore_regs(ptr, ctxsave_regs_mpe,
191 ARRAY_SIZE(ctxsave_regs_mpe));
192
193 ptr = setup_restore_ram(ptr, RC_RAM_SIZE,
194 RC_RAM_LOAD_CMD, RC_RAM_LOAD_DATA);
195
196 ptr = setup_restore_ram(ptr, IRFR_RAM_SIZE,
197 IRFR_RAM_LOAD_CMD, IRFR_RAM_LOAD_DATA);
198
199 restore_end(h, ptr);
200
201 wmb();
202}
203
204
205/*** save ***/
206struct save_info {
207 u32 *ptr;
208 unsigned int save_count;
209 unsigned int restore_count;
210};
211
212static void __init save_begin(struct host1x_hwctx_handler *h, u32 *ptr)
213{
214 /* MPE: when done, increment syncpt to base+1 */
215 ptr[0] = nvhost_opcode_setclass(NV_VIDEO_ENCODE_MPEG_CLASS_ID, 0, 0);
216 ptr[1] = nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_OP_DONE, h->syncpt);
217 /* host: wait for syncpt base+1 */
218 ptr[2] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
219 NV_CLASS_HOST_WAIT_SYNCPT_BASE, 1);
220 ptr[3] = nvhost_class_host_wait_syncpt_base(h->syncpt, h->waitbase, 1);
221 /* host: signal context read thread to start reading */
222 ptr[4] = nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_IMMEDIATE, h->syncpt);
223}
224#define SAVE_BEGIN_SIZE 5
225
226static void __init save_direct(u32 *ptr, u32 start_reg, u32 count)
227{
228 ptr[0] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
229 NV_CLASS_HOST_INDOFF, 1);
230 ptr[1] = nvhost_class_host_indoff_reg_read(NV_HOST_MODULE_MPE,
231 start_reg, true);
232 ptr[2] = nvhost_opcode_nonincr(NV_CLASS_HOST_INDDATA, count);
233}
234#define SAVE_DIRECT_SIZE 3
235
236static void __init save_set_ram_cmd(u32 *ptr, u32 cmd_reg, u32 count)
237{
238 ptr[0] = nvhost_opcode_setclass(NV_VIDEO_ENCODE_MPEG_CLASS_ID,
239 cmd_reg, 1);
240 ptr[1] = count;
241}
242#define SAVE_SET_RAM_CMD_SIZE 2
243
244static void __init save_read_ram_data_nasty(u32 *ptr, u32 data_reg)
245{
246 ptr[0] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
247 NV_CLASS_HOST_INDOFF, 1);
248 ptr[1] = nvhost_class_host_indoff_reg_read(NV_HOST_MODULE_MPE,
249 data_reg, false);
250 ptr[2] = nvhost_opcode_imm(NV_CLASS_HOST_INDDATA, 0);
251 /* write junk data to avoid 'cached problem with register memory' */
252 ptr[3] = nvhost_opcode_setclass(NV_VIDEO_ENCODE_MPEG_CLASS_ID,
253 data_reg, 1);
254 ptr[4] = 0x99;
255}
256#define SAVE_READ_RAM_DATA_NASTY_SIZE 5
257
258static void __init save_end(struct host1x_hwctx_handler *h, u32 *ptr)
259{
260 /* Wait for context read service to finish (cpu incr 3) */
261 ptr[0] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
262 NV_CLASS_HOST_WAIT_SYNCPT_BASE, 1);
263 ptr[1] = nvhost_class_host_wait_syncpt_base(h->syncpt, h->waitbase, 3);
264 /* Advance syncpoint base */
265 ptr[2] = nvhost_opcode_nonincr(NV_CLASS_HOST_INCR_SYNCPT_BASE, 1);
266 ptr[3] = nvhost_class_host_incr_syncpt_base(h->waitbase, 3);
267 /* set class back to the unit */
268 ptr[4] = nvhost_opcode_setclass(NV_VIDEO_ENCODE_MPEG_CLASS_ID, 0, 0);
269}
270#define SAVE_END_SIZE 5
271
272static void __init setup_save_regs(struct save_info *info,
273 const struct hwctx_reginfo *regs,
274 unsigned int nr_regs)
275{
276 const struct hwctx_reginfo *rend = regs + nr_regs;
277 u32 *ptr = info->ptr;
278 unsigned int save_count = info->save_count;
279 unsigned int restore_count = info->restore_count;
280
281 for ( ; regs != rend; ++regs) {
282 u32 offset = regs->offset;
283 u32 count = regs->count;
284 if (regs->type != HWCTX_REGINFO_WRITEBACK) {
285 if (ptr) {
286 save_direct(ptr, offset, count);
287 ptr += SAVE_DIRECT_SIZE;
288 memset(ptr, 0, count * 4);
289 ptr += count;
290 }
291 save_count += (SAVE_DIRECT_SIZE + count);
292 }
293 restore_count += (1 + count);
294 }
295
296 info->ptr = ptr;
297 info->save_count = save_count;
298 info->restore_count = restore_count;
299}
300
301static void __init setup_save_ram_nasty(struct save_info *info, unsigned words,
302 unsigned cmd_reg, unsigned data_reg)
303{
304 u32 *ptr = info->ptr;
305 unsigned int save_count = info->save_count;
306 unsigned int restore_count = info->restore_count;
307 unsigned i;
308
309 if (ptr) {
310 save_set_ram_cmd(ptr, cmd_reg, words);
311 ptr += SAVE_SET_RAM_CMD_SIZE;
312 for (i = words; i; --i) {
313 save_read_ram_data_nasty(ptr, data_reg);
314 ptr += SAVE_READ_RAM_DATA_NASTY_SIZE;
315 }
316 }
317
318 save_count += SAVE_SET_RAM_CMD_SIZE;
319 save_count += words * SAVE_READ_RAM_DATA_NASTY_SIZE;
320 restore_count += (RESTORE_RAM_SIZE + words);
321
322 info->ptr = ptr;
323 info->save_count = save_count;
324 info->restore_count = restore_count;
325}
326
327static void __init setup_save(struct host1x_hwctx_handler *h, u32 *ptr)
328{
329 struct save_info info = {
330 ptr,
331 SAVE_BEGIN_SIZE,
332 RESTORE_BEGIN_SIZE
333 };
334
335 if (info.ptr) {
336 save_begin(h, info.ptr);
337 info.ptr += SAVE_BEGIN_SIZE;
338 }
339
340 setup_save_regs(&info, ctxsave_regs_mpe,
341 ARRAY_SIZE(ctxsave_regs_mpe));
342
343 setup_save_ram_nasty(&info, RC_RAM_SIZE,
344 RC_RAM_READ_CMD, RC_RAM_READ_DATA);
345
346 setup_save_ram_nasty(&info, IRFR_RAM_SIZE,
347 IRFR_RAM_READ_CMD, IRFR_RAM_READ_DATA);
348
349 if (info.ptr) {
350 save_end(h, info.ptr);
351 info.ptr += SAVE_END_SIZE;
352 }
353
354 wmb();
355
356 h->save_size = info.save_count + SAVE_END_SIZE;
357 restore_size = info.restore_count + RESTORE_END_SIZE;
358}
359
360
361static u32 calculate_mpe(u32 word, struct mpe_save_info *msi)
362{
363 u32 buffer_full_read = msi->in[0] & 0x01ffffff;
364 u32 byte_len = msi->in[1];
365 u32 drain = (msi->in[2] >> 2) & 0x007fffff;
366 u32 rep_frame = msi->in[3] & 0x0000ffff;
367 u32 h264_mode = (msi->in[4] >> 11) & 1;
368 int new_buffer_full;
369
370 if (h264_mode)
371 byte_len >>= 3;
372 new_buffer_full = buffer_full_read + byte_len - (drain * 4);
373 msi->out[0] = max(0, new_buffer_full);
374 msi->out[1] = rep_frame;
375 if (rep_frame == 0)
376 word &= 0xffff0000;
377 return word;
378}
379
380static u32 *save_regs(u32 *ptr, unsigned int *pending,
381 struct nvhost_channel *channel,
382 const struct hwctx_reginfo *regs,
383 unsigned int nr_regs,
384 struct mpe_save_info *msi)
385{
386 const struct hwctx_reginfo *rend = regs + nr_regs;
387
388 for ( ; regs != rend; ++regs) {
389 u32 count = regs->count;
390 ++ptr; /* restore incr */
391 if (regs->type == HWCTX_REGINFO_NORMAL) {
392 host1x_drain_read_fifo(channel->aperture,
393 ptr, count, pending);
394 ptr += count;
395 } else {
396 u32 word;
397 if (regs->type == HWCTX_REGINFO_WRITEBACK) {
398 BUG_ON(msi->out_pos >= NR_WRITEBACKS);
399 word = msi->out[msi->out_pos++];
400 } else {
401 host1x_drain_read_fifo(channel->aperture,
402 &word, 1, pending);
403 if (regs->type == HWCTX_REGINFO_STASH) {
404 BUG_ON(msi->in_pos >= NR_STASHES);
405 msi->in[msi->in_pos++] = word;
406 } else {
407 word = calculate_mpe(word, msi);
408 }
409 }
410 *ptr++ = word;
411 }
412 }
413 return ptr;
414}
415
416static u32 *save_ram(u32 *ptr, unsigned int *pending,
417 struct nvhost_channel *channel,
418 unsigned words, unsigned cmd_reg, unsigned data_reg)
419{
420 int err = 0;
421 ptr += RESTORE_RAM_SIZE;
422 err = host1x_drain_read_fifo(channel->aperture, ptr, words, pending);
423 WARN_ON(err);
424 return ptr + words;
425}
426
427
428/*** ctxmpe ***/
429
430static struct nvhost_hwctx *ctxmpe_alloc(struct nvhost_hwctx_handler *h,
431 struct nvhost_channel *ch)
432{
433 struct nvmap_client *nvmap = nvhost_get_host(ch->dev)->nvmap;
434 struct host1x_hwctx_handler *p = to_host1x_hwctx_handler(h);
435 struct host1x_hwctx *ctx;
436
437 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
438 if (!ctx)
439 return NULL;
440 ctx->restore = nvmap_alloc(nvmap, restore_size * 4, 32,
441 NVMAP_HANDLE_WRITE_COMBINE, 0);
442 if (IS_ERR_OR_NULL(ctx->restore)) {
443 kfree(ctx);
444 return NULL;
445 }
446
447 ctx->restore_virt = nvmap_mmap(ctx->restore);
448 if (!ctx->restore_virt) {
449 nvmap_free(nvmap, ctx->restore);
450 kfree(ctx);
451 return NULL;
452 }
453
454 kref_init(&ctx->hwctx.ref);
455 ctx->hwctx.h = &p->h;
456 ctx->hwctx.channel = ch;
457 ctx->hwctx.valid = false;
458 ctx->save_incrs = 3;
459 ctx->save_thresh = 2;
460 ctx->restore_phys = nvmap_pin(nvmap, ctx->restore);
461 ctx->restore_size = restore_size;
462 ctx->restore_incrs = 1;
463
464 setup_restore(p, ctx->restore_virt);
465
466 return &ctx->hwctx;
467}
468
469static void ctxmpe_get(struct nvhost_hwctx *ctx)
470{
471 kref_get(&ctx->ref);
472}
473
474static void ctxmpe_free(struct kref *ref)
475{
476 struct nvhost_hwctx *nctx = container_of(ref, struct nvhost_hwctx, ref);
477 struct host1x_hwctx *ctx = to_host1x_hwctx(nctx);
478 struct nvmap_client *nvmap =
479 nvhost_get_host(nctx->channel->dev)->nvmap;
480
481 if (ctx->restore_virt)
482 nvmap_munmap(ctx->restore, ctx->restore_virt);
483 nvmap_unpin(nvmap, ctx->restore);
484 nvmap_free(nvmap, ctx->restore);
485 kfree(ctx);
486}
487
488static void ctxmpe_put(struct nvhost_hwctx *ctx)
489{
490 kref_put(&ctx->ref, ctxmpe_free);
491}
492
493static void ctxmpe_save_push(struct nvhost_hwctx *nctx,
494 struct nvhost_cdma *cdma)
495{
496 struct host1x_hwctx *ctx = to_host1x_hwctx(nctx);
497 struct host1x_hwctx_handler *h = host1x_hwctx_handler(ctx);
498 nvhost_cdma_push(cdma,
499 nvhost_opcode_gather(h->save_size),
500 h->save_phys);
501}
502
503static void ctxmpe_save_service(struct nvhost_hwctx *nctx)
504{
505 struct host1x_hwctx *ctx = to_host1x_hwctx(nctx);
506 struct host1x_hwctx_handler *h = host1x_hwctx_handler(ctx);
507
508 u32 *ptr = (u32 *)ctx->restore_virt + RESTORE_BEGIN_SIZE;
509 unsigned int pending = 0;
510 struct mpe_save_info msi;
511
512 msi.in_pos = 0;
513 msi.out_pos = 0;
514
515 ptr = save_regs(ptr, &pending, nctx->channel,
516 ctxsave_regs_mpe, ARRAY_SIZE(ctxsave_regs_mpe), &msi);
517
518 ptr = save_ram(ptr, &pending, nctx->channel,
519 RC_RAM_SIZE, RC_RAM_READ_CMD, RC_RAM_READ_DATA);
520
521 ptr = save_ram(ptr, &pending, nctx->channel,
522 IRFR_RAM_SIZE, IRFR_RAM_READ_CMD, IRFR_RAM_READ_DATA);
523
524 wmb();
525 nvhost_syncpt_cpu_incr(&nvhost_get_host(nctx->channel->dev)->syncpt,
526 h->syncpt);
527}
528
529struct nvhost_hwctx_handler * __init nvhost_mpe_ctxhandler_init(
530 u32 syncpt, u32 waitbase,
531 struct nvhost_channel *ch)
532{
533 struct nvmap_client *nvmap;
534 u32 *save_ptr;
535 struct host1x_hwctx_handler *p;
536
537 p = kmalloc(sizeof(*p), GFP_KERNEL);
538 if (!p)
539 return NULL;
540
541 nvmap = nvhost_get_host(ch->dev)->nvmap;
542
543 p->syncpt = syncpt;
544 p->waitbase = waitbase;
545
546 setup_save(p, NULL);
547
548 p->save_buf = nvmap_alloc(nvmap, p->save_size * 4, 32,
549 NVMAP_HANDLE_WRITE_COMBINE, 0);
550 if (IS_ERR(p->save_buf)) {
551 p->save_buf = NULL;
552 return NULL;
553 }
554
555 save_ptr = nvmap_mmap(p->save_buf);
556 if (!save_ptr) {
557 nvmap_free(nvmap, p->save_buf);
558 p->save_buf = NULL;
559 return NULL;
560 }
561
562 p->save_phys = nvmap_pin(nvmap, p->save_buf);
563
564 setup_save(p, save_ptr);
565
566 p->h.alloc = ctxmpe_alloc;
567 p->h.save_push = ctxmpe_save_push;
568 p->h.save_service = ctxmpe_save_service;
569 p->h.get = ctxmpe_get;
570 p->h.put = ctxmpe_put;
571
572 return &p->h;
573}
574
575int nvhost_mpe_prepare_power_off(struct nvhost_device *dev)
576{
577 return host1x_save_context(dev, NVSYNCPT_MPE);
578}
579
580static int __devinit mpe_probe(struct nvhost_device *dev)
581{
582 return nvhost_client_device_init(dev);
583}
584
585static int __exit mpe_remove(struct nvhost_device *dev)
586{
587 /* Add clean-up */
588 return 0;
589}
590
591static int mpe_suspend(struct nvhost_device *dev, pm_message_t state)
592{
593 return nvhost_client_device_suspend(dev);
594}
595
596static int mpe_resume(struct nvhost_device *dev)
597{
598 dev_info(&dev->dev, "resuming\n");
599 return 0;
600}
601
602struct nvhost_device *mpe_device;
603
604static struct nvhost_driver mpe_driver = {
605 .probe = mpe_probe,
606 .remove = __exit_p(mpe_remove),
607#ifdef CONFIG_PM
608 .suspend = mpe_suspend,
609 .resume = mpe_resume,
610#endif
611 .driver = {
612 .owner = THIS_MODULE,
613 .name = "mpe",
614 }
615};
616
617static int __init mpe_init(void)
618{
619 int err;
620
621 mpe_device = nvhost_get_device("mpe");
622 if (!mpe_device)
623 return -ENXIO;
624
625 err = nvhost_device_register(mpe_device);
626 if (err)
627 return err;
628
629 return nvhost_driver_register(&mpe_driver);
630}
631
632static void __exit mpe_exit(void)
633{
634 nvhost_driver_unregister(&mpe_driver);
635}
636
637module_init(mpe_init);
638module_exit(mpe_exit);