video: tegra: host: Implement Tegra3 3D reg read
[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/host1x01_hardware.h"
28 #include "nvhost_hwctx.h"
29 #include "dev.h"
30 #include "gr3d.h"
31 #include "gr3d_t20.h"
32 #include "gr3d_t30.h"
33 #include "gr3d_t114.h"
34 #include "scale3d.h"
35 #include "bus_client.h"
36 #include "nvhost_channel.h"
37 #include "nvhost_memmgr.h"
38 #include "chip_support.h"
39
40 void nvhost_3dctx_restore_begin(struct host1x_hwctx_handler *p, u32 *ptr)
41 {
42         /* set class to host */
43         ptr[0] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
44                                         host1x_uclass_incr_syncpt_base_r(), 1);
45         /* increment sync point base */
46         ptr[1] = nvhost_class_host_incr_syncpt_base(p->waitbase,
47                         p->restore_incrs);
48         /* set class to 3D */
49         ptr[2] = nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0);
50         /* program PSEQ_QUAD_ID */
51         ptr[3] = nvhost_opcode_imm(AR3D_PSEQ_QUAD_ID, 0);
52 }
53
54 void nvhost_3dctx_restore_direct(u32 *ptr, u32 start_reg, u32 count)
55 {
56         ptr[0] = nvhost_opcode_incr(start_reg, count);
57 }
58
59 void nvhost_3dctx_restore_indirect(u32 *ptr, u32 offset_reg, u32 offset,
60                         u32 data_reg, u32 count)
61 {
62         ptr[0] = nvhost_opcode_imm(offset_reg, offset);
63         ptr[1] = nvhost_opcode_nonincr(data_reg, count);
64 }
65
66 void nvhost_3dctx_restore_end(struct host1x_hwctx_handler *p, u32 *ptr)
67 {
68         /* syncpt increment to track restore gather. */
69         ptr[0] = nvhost_opcode_imm_incr_syncpt(
70                         host1x_uclass_incr_syncpt_cond_op_done_v(), p->syncpt);
71 }
72
73 /*** ctx3d ***/
74 struct host1x_hwctx *nvhost_3dctx_alloc_common(struct host1x_hwctx_handler *p,
75                 struct nvhost_channel *ch, bool map_restore)
76 {
77         struct mem_mgr *memmgr = nvhost_get_host(ch->dev)->memmgr;
78         struct host1x_hwctx *ctx;
79
80         ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
81         if (!ctx)
82                 return NULL;
83         ctx->restore = mem_op().alloc(memmgr, p->restore_size * 4, 32,
84                 map_restore ? mem_mgr_flag_write_combine
85                             : mem_mgr_flag_uncacheable);
86         if (IS_ERR_OR_NULL(ctx->restore)) {
87                 ctx->restore = NULL;
88                 goto fail;
89         }
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 nvhost_channel_save_context(dev->channel);
154 }
155
156 enum gr3d_ip_ver {
157         gr3d_01 = 1,
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         int (*read_reg)(struct nvhost_device *dev, struct nvhost_channel *ch,
173                         struct nvhost_hwctx *hwctx, u32 offset, u32 *value);
174 };
175
176 static const struct gr3d_desc gr3d[] = {
177         [gr3d_01] = {
178                 .finalize_poweron = NULL,
179                 .busy = NULL,
180                 .idle = NULL,
181                 .suspend_ndev = NULL,
182                 .init = NULL,
183                 .deinit = NULL,
184                 .prepare_poweroff = nvhost_gr3d_prepare_power_off,
185                 .alloc_hwctx_handler = nvhost_gr3d_t20_ctxhandler_init,
186                 .read_reg = nvhost_gr3d_t20_read_reg,
187         },
188         [gr3d_02] = {
189                 .finalize_poweron = NULL,
190                 .busy = nvhost_scale3d_notify_busy,
191                 .idle = nvhost_scale3d_notify_idle,
192                 .suspend_ndev = nvhost_scale3d_suspend,
193                 .init = nvhost_scale3d_init,
194                 .deinit = nvhost_scale3d_deinit,
195                 .prepare_poweroff = nvhost_gr3d_prepare_power_off,
196                 .alloc_hwctx_handler = nvhost_gr3d_t30_ctxhandler_init,
197                 .read_reg = nvhost_gr3d_t30_read_reg,
198         },
199         [gr3d_03] = {
200                 .busy = nvhost_scale3d_notify_busy,
201                 .idle = nvhost_scale3d_notify_idle,
202                 .suspend_ndev = nvhost_scale3d_suspend,
203                 .init = nvhost_gr3d_t114_init,
204                 .deinit = nvhost_gr3d_t114_deinit,
205                 .prepare_poweroff = nvhost_gr3d_t114_prepare_power_off,
206                 .finalize_poweron = nvhost_gr3d_t114_finalize_power_on,
207                 .alloc_hwctx_handler = nvhost_gr3d_t114_ctxhandler_init,
208                 .read_reg = nvhost_gr3d_t20_read_reg,
209         },
210 };
211
212 static struct nvhost_device_id gr3d_id[] = {
213         { "gr3d", gr3d_01 },
214         { "gr3d", gr3d_02 },
215         { "gr3d", gr3d_03 },
216         { },
217 };
218
219 MODULE_DEVICE_TABLE(nvhost, gr3d_id);
220
221 static int __devinit gr3d_probe(struct nvhost_device *dev,
222         struct nvhost_device_id *id_table)
223 {
224         int index = 0;
225         struct nvhost_driver *drv = to_nvhost_driver(dev->dev.driver);
226
227         index = id_table->version;
228
229         drv->finalize_poweron           = gr3d[index].finalize_poweron;
230         drv->busy                       = gr3d[index].busy;
231         drv->idle                       = gr3d[index].idle;
232         drv->suspend_ndev               = gr3d[index].suspend_ndev;
233         drv->init                       = gr3d[index].init;
234         drv->deinit                     = gr3d[index].deinit;
235         drv->prepare_poweroff           = gr3d[index].prepare_poweroff;
236         drv->alloc_hwctx_handler        = gr3d[index].alloc_hwctx_handler;
237         drv->read_reg                   = gr3d[index].read_reg;
238
239         return nvhost_client_device_init(dev);
240 }
241
242 static int __exit gr3d_remove(struct nvhost_device *dev)
243 {
244         /* Add clean-up */
245         return 0;
246 }
247
248 #ifdef CONFIG_PM
249 static int gr3d_suspend(struct nvhost_device *dev, pm_message_t state)
250 {
251         return nvhost_client_device_suspend(dev);
252 }
253
254 static int gr3d_resume(struct nvhost_device *dev)
255 {
256         dev_info(&dev->dev, "resuming\n");
257         return 0;
258 }
259 #endif
260
261 static struct nvhost_driver gr3d_driver = {
262         .probe = gr3d_probe,
263         .remove = __exit_p(gr3d_remove),
264 #ifdef CONFIG_PM
265         .suspend = gr3d_suspend,
266         .resume = gr3d_resume,
267 #endif
268         .driver = {
269                 .owner = THIS_MODULE,
270                 .name = "gr3d",
271         },
272         .id_table = gr3d_id,
273 };
274
275 static int __init gr3d_init(void)
276 {
277         return nvhost_driver_register(&gr3d_driver);
278 }
279
280 static void __exit gr3d_exit(void)
281 {
282         nvhost_driver_unregister(&gr3d_driver);
283 }
284
285 module_init(gr3d_init);
286 module_exit(gr3d_exit);