a78926f0d3d7182353b6d231d73820f2b25c7aa1
[linux-3.10.git] / drivers / video / tegra / host / vic03 / vic03.c
1 /*
2  * drivers/video/tegra/host/vic/vic03.c
3  *
4  * Tegra VIC03 Module Support
5  *
6  * Copyright (c) 2011-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 <linux/slab.h>         /* for kzalloc */
22 #include <asm/byteorder.h>      /* for parsing ucode image wrt endianness */
23 #include <linux/delay.h>        /* for udelay */
24 #include <linux/export.h>
25 #include <linux/scatterlist.h>
26 #include <linux/nvmap.h>
27 #include <linux/of.h>
28 #include <linux/of_device.h>
29 #include <linux/of_platform.h>
30
31 #include "dev.h"
32 #include "class_ids.h"
33 #include "bus_client.h"
34 #include "nvhost_as.h"
35 #include "nvhost_acm.h"
36 #include "nvhost_scale.h"
37
38 #include "host1x/host1x_hwctx.h"
39
40 #include "vic03.h"
41 #include "hw_flcn_vic03.h"
42 #include "hw_tfbif_vic03.h"
43
44 #include "t124/hardware_t124.h" /* for nvhost opcodes*/
45
46 #include <mach/pm_domains.h>
47
48 #include "../../../../../arch/arm/mach-tegra/iomap.h"
49
50 static struct resource vic03_resources[] = {
51 {
52         .name = "base",
53         .start = TEGRA_VIC_BASE,
54         .end = TEGRA_VIC_BASE + TEGRA_VIC_SIZE - 1,
55         .flags = IORESOURCE_MEM,
56 },
57 };
58
59 struct nvhost_device_data vic03_info = {
60         /*.syncpts       = BIT(NVSYNCPT_VIC),*/
61         /*.modulemutexes = BIT(NVMODMUTEX_VIC),*/
62         .clocks = {{"vic03", UINT_MAX}, {"emc", UINT_MAX}, {} },
63         NVHOST_MODULE_NO_POWERGATE_IDS,
64         NVHOST_DEFAULT_CLOCKGATE_DELAY,
65         .moduleid      = NVHOST_MODULE_VIC,
66         .alloc_hwctx_handler = nvhost_vic03_alloc_hwctx_handler,
67 };
68
69 struct platform_device tegra_vic03_device = {
70         .name          = "vic03",
71         .num_resources = 1,
72         .resource      = vic03_resources,
73         .dev           = {
74                 .platform_data = &vic03_info,
75         },
76 };
77 static inline struct vic03 *get_vic03(struct platform_device *dev)
78 {
79         return (struct vic03 *)nvhost_get_private_data(dev);
80 }
81 static inline void set_vic03(struct platform_device *dev, struct vic03 *vic03)
82 {
83         nvhost_set_private_data(dev, vic03);
84 }
85
86 #define VIC_IDLE_TIMEOUT_DEFAULT        10000   /* 10 milliseconds */
87 #define VIC_IDLE_CHECK_PERIOD   10              /* 10 usec */
88 static int vic03_flcn_wait_idle(struct platform_device *dev,
89                                 u32 *timeout)
90 {
91         struct vic03 *v = get_vic03(dev);
92
93         nvhost_dbg_fn("");
94
95         if (!*timeout)
96                 *timeout = VIC_IDLE_TIMEOUT_DEFAULT;
97
98         do {
99                 u32 check = min_t(u32, VIC_IDLE_CHECK_PERIOD, *timeout);
100                 u32 w = vic03_readl(v, flcn_idlestate_r());
101
102                 if (!w) {
103                         nvhost_dbg_fn("done");
104                         return 0;
105                 }
106                 udelay(VIC_IDLE_CHECK_PERIOD);
107                 *timeout -= check;
108         } while (*timeout);
109
110         dev_err(&dev->dev, "vic03 flcn idle timeout");
111
112         return -1;
113 }
114
115 static int vic03_flcn_dma_wait_idle(struct platform_device *dev, u32 *timeout)
116 {
117         struct vic03 *v = get_vic03(dev);
118         nvhost_dbg_fn("");
119
120         if (!*timeout)
121                 *timeout = VIC_IDLE_TIMEOUT_DEFAULT;
122
123         do {
124                 u32 check = min_t(u32, VIC_IDLE_CHECK_PERIOD, *timeout);
125                 u32 dmatrfcmd = vic03_readl(v, flcn_dmatrfcmd_r());
126                 u32 idle_v = flcn_dmatrfcmd_idle_v(dmatrfcmd);
127
128                 if (flcn_dmatrfcmd_idle_true_v() == idle_v) {
129                         nvhost_dbg_fn("done");
130                         return 0;
131                 }
132                 udelay(VIC_IDLE_CHECK_PERIOD);
133                 *timeout -= check;
134         } while (*timeout);
135
136         dev_err(&dev->dev, "vic03 dma idle timeout");
137
138         return -1;
139 }
140
141
142 static int vic03_flcn_dma_pa_to_internal_256b(struct platform_device *dev,
143                                               phys_addr_t pa,
144                                               u32 internal_offset,
145                                               bool imem)
146 {
147         struct vic03 *v = get_vic03(dev);
148
149         u32 cmd = flcn_dmatrfcmd_size_256b_f();
150         u32 pa_offset =  flcn_dmatrffboffs_offs_f(pa);
151         u32 i_offset = flcn_dmatrfmoffs_offs_f(internal_offset);
152         u32 timeout = 0; /* default*/
153
154         if (imem)
155                 cmd |= flcn_dmatrfcmd_imem_true_f();
156
157         vic03_writel(v, flcn_dmatrfmoffs_r(), i_offset);
158         vic03_writel(v, flcn_dmatrffboffs_r(), pa_offset);
159         vic03_writel(v, flcn_dmatrfcmd_r(), cmd);
160
161         return vic03_flcn_dma_wait_idle(dev, &timeout);
162
163 }
164
165 static int vic03_setup_ucode_image(struct platform_device *dev,
166                                    u32 *ucode_ptr,
167                                    const struct firmware *ucode_fw)
168 {
169         struct vic03 *v = get_vic03(dev);
170         /* image data is little endian. */
171         struct ucode_v1_vic03 ucode;
172         int w;
173
174         /* copy the whole thing taking into account endianness */
175         for (w = 0; w < ucode_fw->size/sizeof(u32); w++)
176                 ucode_ptr[w] = le32_to_cpu(((u32 *)ucode_fw->data)[w]);
177
178         ucode.bin_header = (struct ucode_bin_header_v1_vic03 *)ucode_ptr;
179         /* endian problems would show up right here */
180         if (ucode.bin_header->bin_magic != 0x10de) {
181                 dev_err(&dev->dev,
182                            "failed to get vic03 firmware magic");
183                 return -EINVAL;
184         }
185         if (ucode.bin_header->bin_ver != 1) {
186                 dev_err(&dev->dev,
187                            "unsupported firmware version");
188                 return -ENOENT;
189         }
190         /* shouldn't be bigger than what firmware thinks */
191         if (ucode.bin_header->bin_size > ucode_fw->size) {
192                 dev_err(&dev->dev,
193                            "ucode image size inconsistency");
194                 return -EINVAL;
195         }
196
197         nvhost_dbg_info("vic03 ucode bin header: magic:0x%x ver:%d size:%d",
198                         ucode.bin_header->bin_magic,
199                         ucode.bin_header->bin_ver,
200                         ucode.bin_header->bin_size);
201         nvhost_dbg_info("vic03 ucode bin header: os bin (header,data) offset size: 0x%x, 0x%x %d",
202                         ucode.bin_header->os_bin_header_offset,
203                         ucode.bin_header->os_bin_data_offset,
204                         ucode.bin_header->os_bin_size);
205         nvhost_dbg_info("vic03 ucode bin header: fce bin (header,data) offset size: 0x%x, 0x%x %d",
206                         ucode.bin_header->fce_bin_header_offset,
207                         ucode.bin_header->fce_bin_data_offset,
208                         ucode.bin_header->fce_bin_size);
209
210         ucode.os_header = (struct ucode_os_header_v1_vic03 *)
211                 (((void *)ucode_ptr) + ucode.bin_header->os_bin_header_offset);
212
213         nvhost_dbg_info("vic03 os ucode header: os code (offset,size): 0x%x, 0x%x",
214                         ucode.os_header->os_code_offset,
215                         ucode.os_header->os_code_size);
216         nvhost_dbg_info("vic03 os ucode header: os data (offset,size): 0x%x, 0x%x",
217                         ucode.os_header->os_data_offset,
218                         ucode.os_header->os_data_size);
219         nvhost_dbg_info("vic03 os ucode header: num apps: %d", ucode.os_header->num_apps);
220
221         ucode.fce_header = (struct ucode_fce_header_v1_vic03 *)
222                 (((void *)ucode_ptr) + ucode.bin_header->fce_bin_header_offset);
223
224         nvhost_dbg_info("vic03 fce ucode header: offset, buffer_size, size: 0x%x 0x%x 0x%x",
225                         ucode.fce_header->fce_ucode_offset,
226                         ucode.fce_header->fce_ucode_buffer_size,
227                         ucode.fce_header->fce_ucode_size);
228
229         v->ucode.os.size = ucode.bin_header->os_bin_size;
230         v->ucode.os.bin_data_offset = ucode.bin_header->os_bin_data_offset;
231         v->ucode.os.code_offset = ucode.os_header->os_code_offset;
232         v->ucode.os.data_offset = ucode.os_header->os_data_offset;
233         v->ucode.os.data_size   = ucode.os_header->os_data_size;
234
235         v->ucode.fce.size        = ucode.fce_header->fce_ucode_size;
236         v->ucode.fce.data_offset = ucode.bin_header->fce_bin_data_offset;
237
238         return 0;
239 }
240
241 static int vic03_read_ucode(struct platform_device *dev)
242 {
243         struct vic03 *v = get_vic03(dev);
244         struct mem_mgr *nvmap_c = v->host->memmgr;
245         const struct firmware *ucode_fw;
246         void *ucode_ptr = 0;
247         int err;
248
249         ucode_fw = nvhost_client_request_firmware(dev, VIC03_UCODE_FW_NAME);
250         if (IS_ERR_OR_NULL(ucode_fw)) {
251                 nvhost_dbg_fn("request firmware failed");
252                 dev_err(&dev->dev, "failed to get vic03 firmware\n");
253                 err = -ENOENT;
254                 return err;
255         }
256
257         /* allocate pages for ucode */
258         v->ucode.mem_r = nvhost_memmgr_alloc(nvmap_c,
259                                              roundup(ucode_fw->size, PAGE_SIZE),
260                                              PAGE_SIZE,
261                                              mem_mgr_flag_uncacheable,
262                                              0);
263         if (IS_ERR(v->ucode.mem_r)) {
264                 nvhost_dbg_fn("nvmap alloc failed");
265                 err = PTR_ERR(v->ucode.mem_r);
266                 v->ucode.mem_r = NULL;
267                 goto clean_up;
268         }
269
270         ucode_ptr = nvhost_memmgr_mmap(v->ucode.mem_r);
271         if (!ucode_ptr) {
272                 nvhost_dbg_fn("nvmap mmap failed");
273                 err = -ENOMEM;
274                 goto clean_up;
275         }
276
277         err = vic03_setup_ucode_image(dev, ucode_ptr, ucode_fw);
278         if (err) {
279                 dev_err(&dev->dev, "failed to parse firmware image\n");
280                 return err;
281         }
282
283         v->ucode.valid = true;
284
285         release_firmware(ucode_fw);
286
287         return 0;
288
289  clean_up:
290         if (ucode_ptr)
291                 nvhost_memmgr_munmap(v->ucode.mem_r, ucode_ptr);
292         if (v->ucode.mem_r) {
293                 nvhost_memmgr_put(nvmap_c, v->ucode.mem_r);
294                 v->ucode.mem_r = NULL;
295         }
296         release_firmware(ucode_fw);
297         return err;
298 }
299
300 static int vic03_boot(struct platform_device *dev)
301 {
302         struct vic03 *v = get_vic03(dev);
303         u32 fifoctrl, timeout;
304         u32 offset;
305         int err = 0;
306
307         /* check if firmware is loaded or not */
308         if (!v)
309                 return -ENOMEDIUM;
310
311         vic03_writel(v, flcn_dmactl_r(), 0);
312
313         /* FIXME : disable clock gating, remove when clock gating problem is resolved from MCCIF*/
314         fifoctrl = vic03_readl(v, tfbif_mccif_fifoctrl_r());
315
316         fifoctrl |= tfbif_mccif_fifoctrl_rclk_override_enable_f() |
317                 tfbif_mccif_fifoctrl_wclk_override_enable_f();
318         vic03_writel(v, tfbif_mccif_fifoctrl_r(), fifoctrl);
319
320         vic03_writel(v, flcn_dmatrfbase_r(), (v->ucode.pa + v->ucode.os.bin_data_offset) >> 8);
321
322         for (offset = 0; offset < v->ucode.os.data_size; offset += 256)
323                 vic03_flcn_dma_pa_to_internal_256b(dev,
324                                            v->ucode.os.data_offset + offset,
325                                            offset, false);
326
327         vic03_flcn_dma_pa_to_internal_256b(dev, v->ucode.os.code_offset,
328                                            0, true);
329
330         /* setup falcon interrupts and enable interface */
331         vic03_writel(v, flcn_irqmset_r(), (flcn_irqmset_ext_f(0xff)    |
332                                            flcn_irqmset_swgen1_set_f() |
333                                            flcn_irqmset_swgen0_set_f() |
334                                            flcn_irqmset_exterr_set_f() |
335                                            flcn_irqmset_halt_set_f()   |
336                                            flcn_irqmset_wdtmr_set_f()));
337         vic03_writel(v, flcn_irqdest_r(), (flcn_irqdest_host_ext_f(0xff) |
338                                            flcn_irqdest_host_swgen1_host_f() |
339                                            flcn_irqdest_host_swgen0_host_f() |
340                                            flcn_irqdest_host_exterr_host_f() |
341                                            flcn_irqdest_host_halt_host_f()));
342         vic03_writel(v, flcn_itfen_r(), (flcn_itfen_mthden_enable_f() |
343                                         flcn_itfen_ctxen_enable_f()));
344
345         /* boot falcon */
346         vic03_writel(v, flcn_bootvec_r(), flcn_bootvec_vec_f(0));
347         vic03_writel(v, flcn_cpuctl_r(), flcn_cpuctl_startcpu_true_f());
348
349         timeout = 0; /* default */
350
351         err = vic03_flcn_wait_idle(dev, &timeout);
352         if (err != 0) {
353                 dev_err(&dev->dev, "boot failed due to timeout");
354                 return err;
355         }
356
357         return 0;
358 }
359
360 int nvhost_vic03_init(struct platform_device *dev)
361 {
362         int err = 0;
363         struct nvhost_device_data *pdata = nvhost_get_devdata(dev);
364         struct vic03 *v = get_vic03(dev);
365
366         nvhost_dbg_fn("in dev:%p v:%p", dev, v);
367
368         if (!v) {
369                 nvhost_dbg_fn("allocating vic03 support");
370                 v = kzalloc(sizeof(*v), GFP_KERNEL);
371                 if (!v) {
372                         dev_err(&dev->dev, "couldn't alloc vic03 support");
373                         return -ENOMEM;
374                 }
375                 set_vic03(dev, v);
376         }
377         nvhost_dbg_fn("primed dev:%p v:%p", dev, v);
378
379         v->host = nvhost_get_host(dev);
380         v->regs = pdata->aperture[0];
381
382         if (!v->ucode.valid)
383                 err = vic03_read_ucode(dev);
384
385         if (err) {
386                 nvhost_err(&dev->dev, "ucode image is not valid");
387                 return err;
388         }
389
390         v->ucode.sgt = nvhost_memmgr_pin(v->host->memmgr, v->ucode.mem_r);
391         if (IS_ERR(v->ucode.sgt)) {
392                 nvhost_err(&dev->dev, "nvmap pin failed for ucode, %ld",
393                                 PTR_ERR(v->ucode.sgt));
394                 return PTR_ERR(v->ucode.sgt);
395         }
396         v->ucode.pa = sg_dma_address(v->ucode.sgt->sgl);
397
398         if (!pdata->can_powergate) {
399                 nvhost_module_busy(dev);
400                 err = vic03_boot(dev);
401                 nvhost_module_idle(dev);
402         }
403
404         if (err)
405                 goto clean_up;
406
407         if (pdata->scaling_init)
408                 nvhost_scale_hw_init(dev);
409
410         return 0;
411
412  clean_up:
413         nvhost_err(&dev->dev, "failed");
414         nvhost_memmgr_unpin(nvhost_get_host(dev)->memmgr, v->ucode.mem_r,
415                             v->ucode.sgt);
416         return err;
417 }
418
419 void nvhost_vic03_deinit(struct platform_device *dev)
420 {
421
422         struct vic03 *v = get_vic03(dev);
423         struct nvhost_device_data *pdata = nvhost_get_devdata(dev);
424
425         if (pdata->scaling_init)
426                 nvhost_scale_hw_deinit(dev);
427
428         /* unpin, free ucode memory */
429         if (v->ucode.mem_r) {
430                 nvhost_memmgr_unpin(v->host->memmgr, v->ucode.mem_r,
431                                     v->ucode.sgt);
432                 nvhost_memmgr_put(v->host->memmgr, v->ucode.mem_r);
433                 v->ucode.mem_r = 0;
434         }
435         if (v->regs)
436                 v->regs = 0;
437
438         /* zap, free */
439         set_vic03(dev,0);
440         kfree(v);
441 }
442
443 static struct nvhost_hwctx *vic03_alloc_hwctx(struct nvhost_hwctx_handler *h,
444                 struct nvhost_channel *ch)
445 {
446         struct host1x_hwctx_handler *p = to_host1x_hwctx_handler(h);
447
448         struct vic03 *v = get_vic03(ch->dev);
449         struct mem_mgr *nvmap = nvhost_get_host(ch->dev)->memmgr;
450         struct host1x_hwctx *ctx;
451         bool map_restore = true;
452         u32 *ptr;
453         u32 syncpt = nvhost_get_devdata(ch->dev)->syncpts[0];
454         u32 nvhost_vic03_restore_size = 11; /* number of words written below */
455
456         nvhost_dbg_fn("");
457
458         ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
459         if (!ctx)
460                 return NULL;
461
462         ctx->restore = nvhost_memmgr_alloc(nvmap,
463                                            nvhost_vic03_restore_size * 4, 32,
464                                            map_restore ?
465                                                 mem_mgr_flag_write_combine
466                                               : mem_mgr_flag_uncacheable,
467                                            0);
468         if (IS_ERR_OR_NULL(ctx->restore))
469                 goto fail_alloc;
470
471         if (map_restore) {
472                 ctx->restore_virt = nvhost_memmgr_mmap(ctx->restore);
473                 if (IS_ERR_OR_NULL(ctx->restore_virt))
474                         goto fail_mmap;
475         } else
476                 ctx->restore_virt = NULL;
477
478         ptr = ctx->restore_virt;
479
480         /* set class to vic */
481         ptr[0] = nvhost_opcode_setclass(NV_GRAPHICS_VIC_CLASS_ID, 0, 0);
482
483         /* set app id, fce ucode size, offset */
484         ptr[1] = nvhost_opcode_incr(VIC_UCLASS_METHOD_OFFSET, 2);
485         ptr[2] = NVA0B6_VIDEO_COMPOSITOR_SET_APPLICATION_ID  >> 2;
486         ptr[3] = 1;
487
488         ptr[4] = nvhost_opcode_incr(VIC_UCLASS_METHOD_OFFSET, 2);
489         ptr[5] = NVA0B6_VIDEO_COMPOSITOR_SET_FCE_UCODE_SIZE >> 2;
490         ptr[6] = v->ucode.fce.size;
491
492         ptr[7] = nvhost_opcode_incr(VIC_UCLASS_METHOD_OFFSET, 2);
493         ptr[8] = NVA0B6_VIDEO_COMPOSITOR_SET_FCE_UCODE_OFFSET >> 2;
494         ptr[9] = (v->ucode.pa + v->ucode.fce.data_offset) >> 8;
495
496         /* syncpt increment to track restore gather. */
497         ptr[10] = nvhost_opcode_imm_incr_syncpt(
498                         host1x_uclass_incr_syncpt_cond_op_done_v(),
499                         syncpt);
500
501         kref_init(&ctx->hwctx.ref);
502         ctx->hwctx.h = &p->h;
503         ctx->hwctx.channel = ch;
504         ctx->hwctx.valid = true; /* this is a preconditioning sequence... */
505         ctx->hwctx.save_incrs = 0;
506         ctx->hwctx.save_thresh = 0;
507         ctx->hwctx.save_slots = 0;
508
509         ctx->restore_sgt = nvhost_memmgr_pin(nvmap, ctx->restore);
510         if (IS_ERR_VALUE(ctx->restore_phys))
511                 goto fail_pin;
512         ctx->restore_phys = sg_dma_address(ctx->restore_sgt->sgl);
513
514         ctx->restore_size = nvhost_vic03_restore_size;
515         ctx->hwctx.restore_incrs = 1;
516
517         return &ctx->hwctx;
518
519  fail_pin:
520         if (map_restore)
521                 nvhost_memmgr_munmap(ctx->restore, ctx->restore_virt);
522  fail_mmap:
523         nvhost_memmgr_put(nvmap, ctx->restore);
524  fail_alloc:
525         kfree(ctx);
526         return NULL;
527 }
528
529 static void vic03_free_hwctx(struct kref *ref)
530 {
531         struct nvhost_hwctx *nctx = container_of(ref, struct nvhost_hwctx, ref);
532         struct host1x_hwctx *ctx = to_host1x_hwctx(nctx);
533         struct mem_mgr *nvmap =
534                 nvhost_get_host(nctx->channel->dev)->memmgr;
535
536         if (ctx->restore_virt) {
537                 nvhost_memmgr_munmap(ctx->restore, ctx->restore_virt);
538                 ctx->restore_virt = NULL;
539         }
540         nvhost_memmgr_unpin(nvmap, ctx->restore, ctx->restore_sgt);
541         ctx->restore_phys = 0;
542         nvhost_memmgr_put(nvmap, ctx->restore);
543         ctx->restore = NULL;
544         kfree(ctx);
545 }
546
547 static void vic03_get_hwctx (struct nvhost_hwctx *ctx)
548 {
549         nvhost_dbg_fn("");
550         kref_get(&ctx->ref);
551 }
552 static void vic03_put_hwctx (struct nvhost_hwctx *ctx)
553 {
554         nvhost_dbg_fn("");
555         kref_put(&ctx->ref, vic03_free_hwctx);
556 }
557 static void vic03_save_push_hwctx ( struct nvhost_hwctx *ctx, struct nvhost_cdma *cdma)
558 {
559         nvhost_dbg_fn("");
560 }
561
562 static void ctxvic03_restore_push(struct nvhost_hwctx *nctx,
563                 struct nvhost_cdma *cdma)
564 {
565         struct host1x_hwctx *ctx = to_host1x_hwctx(nctx);
566         nvhost_cdma_push_gather(cdma,
567                 ctx->hwctx.memmgr,
568                 ctx->restore,
569                 0,
570                 nvhost_opcode_gather(ctx->restore_size),
571                 ctx->restore_phys);
572 }
573
574 struct nvhost_hwctx_handler *nvhost_vic03_alloc_hwctx_handler(u32 syncpt,
575         u32 waitbase, struct nvhost_channel *ch)
576 {
577         struct host1x_hwctx_handler *p;
578
579         p = kmalloc(sizeof(*p), GFP_KERNEL);
580         if (!p)
581                 return NULL;
582
583         p->h.syncpt = syncpt;
584         p->h.waitbase = waitbase;
585
586         p->h.alloc = vic03_alloc_hwctx;
587         p->h.get   = vic03_get_hwctx;
588         p->h.put   = vic03_put_hwctx;
589         p->h.save_push = vic03_save_push_hwctx;
590         p->h.restore_push = ctxvic03_restore_push;
591         p->h.save_service = NULL;
592
593         return &p->h;
594 }
595
596 int nvhost_vic03_finalize_poweron(struct platform_device *dev)
597 {
598         return vic03_boot(dev);
599 }
600
601 static struct of_device_id tegra_vic_of_match[] = {
602         { .compatible = "nvidia,tegra124-vic",
603                 .data = (struct nvhost_device_data *)&vic03_info },
604         { },
605 };
606
607 #ifdef CONFIG_PM_GENERIC_DOMAINS
608 static int vic03_unpowergate(struct generic_pm_domain *domain)
609 {
610         struct nvhost_device_data *pdata;
611
612         pdata = container_of(domain, struct nvhost_device_data, pd);
613         return nvhost_module_power_on(pdata->pdev);
614 }
615
616 static int vic03_powergate(struct generic_pm_domain *domain)
617 {
618         struct nvhost_device_data *pdata;
619
620         pdata = container_of(domain, struct nvhost_device_data, pd);
621         return nvhost_module_power_off(pdata->pdev);
622 }
623 #endif
624
625 static int vic03_probe(struct platform_device *dev)
626 {
627         int err;
628         struct nvhost_device_data *pdata = NULL;
629
630         if (dev->dev.of_node) {
631                 const struct of_device_id *match;
632
633                 match = of_match_device(tegra_vic_of_match, &dev->dev);
634                 if (match)
635                         pdata = (struct nvhost_device_data *)match->data;
636         } else
637                 pdata = (struct nvhost_device_data *)dev->dev.platform_data;
638
639         nvhost_dbg_fn("dev:%p pdata:%p", dev, pdata);
640
641         pdata->init                     = nvhost_vic03_init;
642         pdata->deinit                   = nvhost_vic03_deinit;
643         pdata->finalize_poweron         = nvhost_vic03_finalize_poweron;
644         pdata->alloc_hwctx_handler      = nvhost_vic03_alloc_hwctx_handler;
645
646         /* VIC scaling is disabled by default. remove #if/endif to enable */
647 #if 0
648         pdata->scaling_init             = nvhost_scale_init;
649         pdata->scaling_deinit           = nvhost_scale_deinit;
650         pdata->idle                     = nvhost_scale_notify_idle;
651         pdata->busy                     = nvhost_scale_notify_busy;
652         pdata->actmon_regs              = HOST1X_CHANNEL_ACTMON2_REG_BASE;
653         pdata->actmon_enabled           = true;
654 #endif
655
656         pdata->pdev = dev;
657
658         mutex_init(&pdata->lock);
659
660         platform_set_drvdata(dev, pdata);
661         dev->dev.platform_data = NULL;
662
663         nvhost_module_init(dev);
664
665 #ifdef CONFIG_PM_GENERIC_DOMAINS
666         pdata->pd.name = "vic03";
667         pdata->pd.power_off = vic03_powergate;
668         pdata->pd.power_on = vic03_unpowergate;
669         pdata->pd.dev_ops.start = nvhost_module_enable_clk;
670         pdata->pd.dev_ops.stop = nvhost_module_disable_clk;
671
672         err = nvhost_module_add_domain(&pdata->pd, dev);
673
674         /* overwrite save/restore fptrs set by pm_genpd_init */
675         pdata->pd.domain.ops.suspend = nvhost_client_device_suspend;
676         pdata->pd.domain.ops.resume = nvhost_client_device_resume;
677         pdata->pd.dev_ops.restore_state = nvhost_module_finalize_poweron;
678 #endif
679
680         if (pdata->clockgate_delay) {
681                 pm_runtime_set_autosuspend_delay(&dev->dev,
682                         pdata->clockgate_delay);
683                 pm_runtime_use_autosuspend(&dev->dev);
684         }
685         pm_runtime_enable(&dev->dev);
686
687         err = nvhost_client_device_get_resources(dev);
688         if (err)
689                 return err;
690
691         pm_runtime_get_sync(&dev->dev);
692
693         err = nvhost_client_device_init(dev);
694         if (err) {
695                 nvhost_dbg_fn("failed to init client device for %s",
696                               dev->name);
697                 pm_runtime_put(&dev->dev);
698                 return err;
699         }
700
701         err = nvhost_as_init_device(dev);
702         if (err) {
703                 nvhost_dbg_fn("failed to init client address space"
704                               " device for %s", dev->name);
705                 pm_runtime_put(&dev->dev);
706                 return err;
707         }
708
709         if (pdata->clockgate_delay)
710                 pm_runtime_put_sync_autosuspend(&dev->dev);
711         else
712                 pm_runtime_put(&dev->dev);
713
714         return 0;
715 }
716
717 static int __exit vic03_remove(struct platform_device *dev)
718 {
719         /* Add clean-up */
720         return 0;
721 }
722
723 static struct platform_driver vic03_driver = {
724         .probe = vic03_probe,
725         .remove = __exit_p(vic03_remove),
726         .driver = {
727                 .owner = THIS_MODULE,
728                 .name = "vic03",
729 #ifdef CONFIG_OF
730                 .of_match_table = tegra_vic_of_match,
731 #endif
732         }
733 };
734
735 static int __init vic03_init(void)
736 {
737         return platform_driver_register(&vic03_driver);
738 }
739
740 static void __exit vic03_exit(void)
741 {
742         platform_driver_unregister(&vic03_driver);
743 }
744
745 module_init(vic03_init);
746 module_exit(vic03_exit);