video: tegra: host: Register devices in SoC files
[linux-2.6.git] / drivers / video / tegra / host / gr3d / gr3d.c
1 /*
2  * drivers/video/tegra/host/gr3d/gr3d.c
3  *
4  * Tegra Graphics Host 3D
5  *
6  * Copyright (c) 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 <linux/slab.h>
22 #include <linux/export.h>
23 #include <linux/module.h>
24 #include <mach/gpufuse.h>
25
26 #include "t20/t20.h"
27 #include "host1x/host1x_channel.h"
28 #include "host1x/host1x_hardware.h"
29 #include "host1x/host1x_syncpt.h"
30 #include "nvhost_hwctx.h"
31 #include "dev.h"
32 #include "gr3d.h"
33 #include "gr3d_t20.h"
34 #include "gr3d_t30.h"
35 #include "gr3d_t114.h"
36 #include "scale3d.h"
37 #include "bus_client.h"
38 #include "nvhost_channel.h"
39 #include "nvhost_memmgr.h"
40 #include "chip_support.h"
41
42 void nvhost_3dctx_restore_begin(struct host1x_hwctx_handler *p, u32 *ptr)
43 {
44         /* set class to host */
45         ptr[0] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
46                                         NV_CLASS_HOST_INCR_SYNCPT_BASE, 1);
47         /* increment sync point base */
48         ptr[1] = nvhost_class_host_incr_syncpt_base(p->waitbase,
49                         p->restore_incrs);
50         /* set class to 3D */
51         ptr[2] = nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0);
52         /* program PSEQ_QUAD_ID */
53         ptr[3] = nvhost_opcode_imm(AR3D_PSEQ_QUAD_ID, 0);
54 }
55
56 void nvhost_3dctx_restore_direct(u32 *ptr, u32 start_reg, u32 count)
57 {
58         ptr[0] = nvhost_opcode_incr(start_reg, count);
59 }
60
61 void nvhost_3dctx_restore_indirect(u32 *ptr, u32 offset_reg, u32 offset,
62                         u32 data_reg, u32 count)
63 {
64         ptr[0] = nvhost_opcode_imm(offset_reg, offset);
65         ptr[1] = nvhost_opcode_nonincr(data_reg, count);
66 }
67
68 void nvhost_3dctx_restore_end(struct host1x_hwctx_handler *p, u32 *ptr)
69 {
70         /* syncpt increment to track restore gather. */
71         ptr[0] = nvhost_opcode_imm_incr_syncpt(
72                         NV_SYNCPT_OP_DONE, p->syncpt);
73 }
74
75 /*** ctx3d ***/
76 struct host1x_hwctx *nvhost_3dctx_alloc_common(struct host1x_hwctx_handler *p,
77                 struct nvhost_channel *ch, bool map_restore)
78 {
79         struct mem_mgr *memmgr = nvhost_get_host(ch->dev)->memmgr;
80         struct host1x_hwctx *ctx;
81
82         ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
83         if (!ctx)
84                 return NULL;
85         ctx->restore = mem_op().alloc(memmgr, p->restore_size * 4, 32,
86                 map_restore ? mem_mgr_flag_write_combine
87                             : mem_mgr_flag_uncacheable);
88         if (IS_ERR_OR_NULL(ctx->restore))
89                 goto fail;
90
91         if (map_restore) {
92                 ctx->restore_virt = mem_op().mmap(ctx->restore);
93                 if (!ctx->restore_virt)
94                         goto fail;
95         } else
96                 ctx->restore_virt = NULL;
97
98         kref_init(&ctx->hwctx.ref);
99         ctx->hwctx.h = &p->h;
100         ctx->hwctx.channel = ch;
101         ctx->hwctx.valid = false;
102         ctx->save_incrs = p->save_incrs;
103         ctx->save_thresh = p->save_thresh;
104         ctx->save_slots = p->save_slots;
105         ctx->restore_phys = mem_op().pin(memmgr, ctx->restore);
106         if (IS_ERR_VALUE(ctx->restore_phys))
107                 goto fail;
108
109         ctx->restore_size = p->restore_size;
110         ctx->restore_incrs = p->restore_incrs;
111         return ctx;
112
113 fail:
114         if (map_restore && ctx->restore_virt) {
115                 mem_op().munmap(ctx->restore, ctx->restore_virt);
116                 ctx->restore_virt = NULL;
117         }
118         mem_op().put(memmgr, ctx->restore);
119         ctx->restore = NULL;
120         kfree(ctx);
121         return NULL;
122 }
123
124 void nvhost_3dctx_get(struct nvhost_hwctx *ctx)
125 {
126         kref_get(&ctx->ref);
127 }
128
129 void nvhost_3dctx_free(struct kref *ref)
130 {
131         struct nvhost_hwctx *nctx = container_of(ref, struct nvhost_hwctx, ref);
132         struct host1x_hwctx *ctx = to_host1x_hwctx(nctx);
133         struct mem_mgr *memmgr = nvhost_get_host(nctx->channel->dev)->memmgr;
134
135         if (ctx->restore_virt) {
136                 mem_op().munmap(ctx->restore, ctx->restore_virt);
137                 ctx->restore_virt = NULL;
138         }
139         mem_op().unpin(memmgr, ctx->restore);
140         ctx->restore_phys = 0;
141         mem_op().put(memmgr, ctx->restore);
142         ctx->restore = NULL;
143         kfree(ctx);
144 }
145
146 void nvhost_3dctx_put(struct nvhost_hwctx *ctx)
147 {
148         kref_put(&ctx->ref, nvhost_3dctx_free);
149 }
150
151 int nvhost_gr3d_prepare_power_off(struct nvhost_device *dev)
152 {
153         return host1x_save_context(dev, NVSYNCPT_3D);
154 }
155
156 enum gr3d_ip_ver {
157         gr3d_01,
158         gr3d_02,
159         gr3d_03,
160 };
161
162 struct gr3d_desc {
163         void (*finalize_poweron)(struct nvhost_device *dev);
164         void (*busy)(struct nvhost_device *);
165         void (*idle)(struct nvhost_device *);
166         void (*suspend_ndev)(struct nvhost_device *);
167         void (*init)(struct nvhost_device *dev);
168         void (*deinit)(struct nvhost_device *dev);
169         int (*prepare_poweroff)(struct nvhost_device *dev);
170         struct nvhost_hwctx_handler *(*alloc_hwctx_handler)(u32 syncpt,
171                         u32 waitbase, struct nvhost_channel *ch);
172 };
173
174 static const struct gr3d_desc gr3d[] = {
175         [gr3d_01] = {
176                 .finalize_poweron = NULL,
177                 .busy = NULL,
178                 .idle = NULL,
179                 .suspend_ndev = NULL,
180                 .init = NULL,
181                 .deinit = NULL,
182                 .prepare_poweroff = nvhost_gr3d_prepare_power_off,
183                 .alloc_hwctx_handler = nvhost_gr3d_t20_ctxhandler_init,
184         },
185         [gr3d_02] = {
186                 .finalize_poweron = NULL,
187                 .busy = nvhost_scale3d_notify_busy,
188                 .idle = nvhost_scale3d_notify_idle,
189                 .suspend_ndev = nvhost_scale3d_suspend,
190                 .init = nvhost_scale3d_init,
191                 .deinit = nvhost_scale3d_deinit,
192                 .prepare_poweroff = nvhost_gr3d_prepare_power_off,
193                 .alloc_hwctx_handler = nvhost_gr3d_t30_ctxhandler_init,
194         },
195         [gr3d_03] = {
196                 .finalize_poweron = NULL,
197                 .busy = nvhost_scale3d_notify_busy,
198                 .idle = nvhost_scale3d_notify_idle,
199                 .suspend_ndev = nvhost_scale3d_suspend,
200                 .init = nvhost_scale3d_init,
201                 .deinit = nvhost_scale3d_deinit,
202                 .prepare_poweroff = nvhost_gr3d_prepare_power_off,
203                 .alloc_hwctx_handler = nvhost_gr3d_t114_ctxhandler_init,
204         },
205 };
206
207 static struct nvhost_device_id gr3d_id[] = {
208         { "gr3d01", gr3d_01 },
209         { "gr3d02", gr3d_02 },
210         { "gr3d03", gr3d_03 },
211         { },
212 };
213
214 MODULE_DEVICE_TABLE(nvhost, gr3d_id);
215
216 static int __devinit gr3d_probe(struct nvhost_device *dev,
217         struct nvhost_device_id *id_table)
218 {
219         int index = 0;
220         struct nvhost_driver *drv = to_nvhost_driver(dev->dev.driver);
221
222         index = id_table->driver_data;
223
224         drv->finalize_poweron           = gr3d[index].finalize_poweron;
225         drv->busy                       = gr3d[index].busy;
226         drv->idle                       = gr3d[index].idle;
227         drv->suspend_ndev               = gr3d[index].suspend_ndev;
228         drv->init                       = gr3d[index].init;
229         drv->deinit                     = gr3d[index].deinit;
230         drv->prepare_poweroff           = gr3d[index].prepare_poweroff;
231         drv->alloc_hwctx_handler        = gr3d[index].alloc_hwctx_handler;
232
233         /* reset device name so that consistent device name can be
234          * found in clock tree */
235         dev->name = "gr3d";
236
237         nvhost_set_register_sets(tegra_gpu_register_sets());
238         return nvhost_client_device_init(dev);
239 }
240
241 static int __exit gr3d_remove(struct nvhost_device *dev)
242 {
243         /* Add clean-up */
244         return 0;
245 }
246
247 static int gr3d_suspend(struct nvhost_device *dev, pm_message_t state)
248 {
249         return nvhost_client_device_suspend(dev);
250 }
251
252 static int gr3d_resume(struct nvhost_device *dev)
253 {
254         dev_info(&dev->dev, "resuming\n");
255         return 0;
256 }
257
258 static struct nvhost_driver gr3d_driver = {
259         .probe = gr3d_probe,
260         .remove = __exit_p(gr3d_remove),
261 #ifdef CONFIG_PM
262         .suspend = gr3d_suspend,
263         .resume = gr3d_resume,
264 #endif
265         .driver = {
266                 .owner = THIS_MODULE,
267                 .name = "gr3d",
268         },
269         .id_table = gr3d_id,
270 };
271
272 static int __init gr3d_init(void)
273 {
274         return nvhost_driver_register(&gr3d_driver);
275 }
276
277 static void __exit gr3d_exit(void)
278 {
279         nvhost_driver_unregister(&gr3d_driver);
280 }
281
282 module_init(gr3d_init);
283 module_exit(gr3d_exit);