blob: 6fbcdee9531a6b63889bdc95bd2ebf4cc738bc31 [file] [log] [blame]
Duy Truonge833aca2013-02-12 13:35:08 -08001/* Copyright (c) 2002,2007-2012, The Linux Foundation. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
Jordan Crousea78c9172011-07-11 13:14:09 -060013
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070014#include <linux/slab.h>
15
16#include "kgsl.h"
17#include "kgsl_sharedmem.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070018#include "adreno.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070019
Carter Cooper7e7f02e2012-02-15 09:36:31 -070020#define KGSL_INIT_REFTIMESTAMP 0x7FFFFFFF
21
Jordan Crouse0e0486f2011-07-28 08:37:58 -060022/* quad for copying GMEM to context shadow */
23#define QUAD_LEN 12
Jordan Crouseb4d31bd2012-02-01 22:11:12 -070024#define QUAD_RESTORE_LEN 14
Jordan Crouse0e0486f2011-07-28 08:37:58 -060025
26static unsigned int gmem_copy_quad[QUAD_LEN] = {
27 0x00000000, 0x00000000, 0x3f800000,
28 0x00000000, 0x00000000, 0x3f800000,
29 0x00000000, 0x00000000, 0x3f800000,
30 0x00000000, 0x00000000, 0x3f800000
31};
32
Jordan Crouseb4d31bd2012-02-01 22:11:12 -070033static unsigned int gmem_restore_quad[QUAD_RESTORE_LEN] = {
34 0x00000000, 0x3f800000, 0x3f800000,
35 0x00000000, 0x00000000, 0x00000000,
36 0x3f800000, 0x00000000, 0x00000000,
37 0x3f800000, 0x00000000, 0x00000000,
38 0x3f800000, 0x3f800000,
39};
40
Jordan Crouse0e0486f2011-07-28 08:37:58 -060041#define TEXCOORD_LEN 8
42
43static unsigned int gmem_copy_texcoord[TEXCOORD_LEN] = {
44 0x00000000, 0x3f800000,
45 0x3f800000, 0x3f800000,
46 0x00000000, 0x00000000,
47 0x3f800000, 0x00000000
48};
49
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070050/*
Jordan Crousea78c9172011-07-11 13:14:09 -060051 * Helper functions
52 * These are global helper functions used by the GPUs during context switch
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070053 */
54
Jordan Crousea78c9172011-07-11 13:14:09 -060055/**
56 * uint2float - convert a uint to IEEE754 single precision float
57 * @ uintval - value to convert
58 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070059
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070060unsigned int uint2float(unsigned int uintval)
61{
62 unsigned int exp, frac = 0;
63
64 if (uintval == 0)
65 return 0;
66
67 exp = ilog2(uintval);
68
69 /* Calculate fraction */
70 if (23 > exp)
71 frac = (uintval & (~(1 << exp))) << (23 - exp);
72
73 /* Exp is biased by 127 and shifted 23 bits */
74 exp = (exp + 127) << 23;
75
76 return exp | frac;
77}
78
Jordan Crouse0e0486f2011-07-28 08:37:58 -060079static void set_gmem_copy_quad(struct gmem_shadow_t *shadow)
80{
81 /* set vertex buffer values */
82 gmem_copy_quad[1] = uint2float(shadow->height);
83 gmem_copy_quad[3] = uint2float(shadow->width);
84 gmem_copy_quad[4] = uint2float(shadow->height);
85 gmem_copy_quad[9] = uint2float(shadow->width);
86
Jordan Crouseb4d31bd2012-02-01 22:11:12 -070087 gmem_restore_quad[5] = uint2float(shadow->height);
88 gmem_restore_quad[7] = uint2float(shadow->width);
Jordan Crouse0e0486f2011-07-28 08:37:58 -060089
90 memcpy(shadow->quad_vertices.hostptr, gmem_copy_quad, QUAD_LEN << 2);
Tarun Karra7e8e1cf2012-02-06 18:23:19 -080091 memcpy(shadow->quad_vertices_restore.hostptr, gmem_restore_quad,
Jordan Crouseb4d31bd2012-02-01 22:11:12 -070092 QUAD_RESTORE_LEN << 2);
Jordan Crouse0e0486f2011-07-28 08:37:58 -060093
94 memcpy(shadow->quad_texcoords.hostptr, gmem_copy_texcoord,
95 TEXCOORD_LEN << 2);
96}
97
98/**
99 * build_quad_vtxbuff - Create a quad for saving/restoring GMEM
100 * @ context - Pointer to the context being created
101 * @ shadow - Pointer to the GMEM shadow structure
102 * @ incmd - Pointer to pointer to the temporary command buffer
103 */
104
105/* quad for saving/restoring gmem */
106void build_quad_vtxbuff(struct adreno_context *drawctxt,
107 struct gmem_shadow_t *shadow, unsigned int **incmd)
108{
109 unsigned int *cmd = *incmd;
110
111 /* quad vertex buffer location (in GPU space) */
112 shadow->quad_vertices.hostptr = cmd;
113 shadow->quad_vertices.gpuaddr = virt2gpu(cmd, &drawctxt->gpustate);
114
115 cmd += QUAD_LEN;
116
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700117 /* Used by A3XX, but define for both to make the code easier */
118 shadow->quad_vertices_restore.hostptr = cmd;
119 shadow->quad_vertices_restore.gpuaddr =
120 virt2gpu(cmd, &drawctxt->gpustate);
121
122 cmd += QUAD_RESTORE_LEN;
123
Jordan Crouse0e0486f2011-07-28 08:37:58 -0600124 /* tex coord buffer location (in GPU space) */
125 shadow->quad_texcoords.hostptr = cmd;
126 shadow->quad_texcoords.gpuaddr = virt2gpu(cmd, &drawctxt->gpustate);
127
128 cmd += TEXCOORD_LEN;
129
130 set_gmem_copy_quad(shadow);
131 *incmd = cmd;
132}
133
Jordan Crousea78c9172011-07-11 13:14:09 -0600134/**
135 * adreno_drawctxt_create - create a new adreno draw context
136 * @device - KGSL device to create the context on
137 * @pagetable - Pagetable for the context
138 * @context- Generic KGSL context structure
139 * @flags - flags for the context (passed from user space)
140 *
141 * Create a new draw context for the 3D core. Return 0 on success,
142 * or error code on failure.
143 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700144int adreno_drawctxt_create(struct kgsl_device *device,
145 struct kgsl_pagetable *pagetable,
146 struct kgsl_context *context, uint32_t flags)
147{
148 struct adreno_context *drawctxt;
149 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
Carter Cooper7ffaba62012-05-24 13:59:53 -0600150 struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700151 int ret;
152
153 drawctxt = kzalloc(sizeof(struct adreno_context), GFP_KERNEL);
154
155 if (drawctxt == NULL)
156 return -ENOMEM;
157
Tarun Karra5bea9c62013-01-27 17:39:17 -0800158 drawctxt->pid = task_pid_nr(current);
159 strlcpy(drawctxt->pid_name, current->comm, TASK_COMM_LEN);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700160 drawctxt->pagetable = pagetable;
161 drawctxt->bin_base_offset = 0;
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700162 drawctxt->id = context->id;
Carter Cooper7ffaba62012-05-24 13:59:53 -0600163 rb->timestamp[context->id] = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700164
Vijay Krishnamoorthybef66932012-01-24 09:32:05 -0700165 if (flags & KGSL_CONTEXT_PREAMBLE)
166 drawctxt->flags |= CTXT_FLAGS_PREAMBLE;
Jordan Crousea78c9172011-07-11 13:14:09 -0600167
Vijay Krishnamoorthybef66932012-01-24 09:32:05 -0700168 if (flags & KGSL_CONTEXT_NO_GMEM_ALLOC)
169 drawctxt->flags |= CTXT_FLAGS_NOGMEMALLOC;
170
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700171 if (flags & KGSL_CONTEXT_PER_CONTEXT_TS)
172 drawctxt->flags |= CTXT_FLAGS_PER_CONTEXT_TS;
173
Vijay Krishnamoorthye80c3462012-08-27 14:07:32 -0700174 if (flags & KGSL_CONTEXT_USER_GENERATED_TS) {
175 if (!(flags & KGSL_CONTEXT_PER_CONTEXT_TS)) {
176 ret = -EINVAL;
177 goto err;
178 }
179 drawctxt->flags |= CTXT_FLAGS_USER_GENERATED_TS;
180 }
181
Tarun Karra83297222013-02-05 19:45:49 -0800182 if (flags & KGSL_CONTEXT_NO_FAULT_TOLERANCE)
183 drawctxt->flags |= CTXT_FLAGS_NO_FAULT_TOLERANCE;
184
Vijay Krishnamoorthybef66932012-01-24 09:32:05 -0700185 ret = adreno_dev->gpudev->ctxt_create(adreno_dev, drawctxt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700186 if (ret)
187 goto err;
188
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700189 kgsl_sharedmem_writel(&device->memstore,
190 KGSL_MEMSTORE_OFFSET(drawctxt->id, ref_wait_ts),
191 KGSL_INIT_REFTIMESTAMP);
Carter Cooper7ffaba62012-05-24 13:59:53 -0600192 kgsl_sharedmem_writel(&device->memstore,
193 KGSL_MEMSTORE_OFFSET(drawctxt->id, ts_cmp_enable), 0);
194 kgsl_sharedmem_writel(&device->memstore,
195 KGSL_MEMSTORE_OFFSET(drawctxt->id, soptimestamp), 0);
196 kgsl_sharedmem_writel(&device->memstore,
197 KGSL_MEMSTORE_OFFSET(drawctxt->id, eoptimestamp), 0);
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700198
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700199 context->devctxt = drawctxt;
200 return 0;
201err:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700202 kfree(drawctxt);
203 return ret;
204}
205
Jordan Crousea78c9172011-07-11 13:14:09 -0600206/**
207 * adreno_drawctxt_destroy - destroy a draw context
208 * @device - KGSL device that owns the context
209 * @context- Generic KGSL context container for the context
210 *
211 * Destroy an existing context. Return 0 on success or error
212 * code on failure.
213 */
214
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700215/* destroy a drawing context */
216
217void adreno_drawctxt_destroy(struct kgsl_device *device,
218 struct kgsl_context *context)
219{
220 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700221 struct adreno_context *drawctxt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700222
Jordan Crouse87239682012-06-19 13:08:22 -0600223 if (context == NULL || context->devctxt == NULL)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700224 return;
225
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700226 drawctxt = context->devctxt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700227 /* deactivate context */
228 if (adreno_dev->drawctxt_active == drawctxt) {
229 /* no need to save GMEM or shader, the context is
230 * being destroyed.
231 */
232 drawctxt->flags &= ~(CTXT_FLAGS_GMEM_SAVE |
233 CTXT_FLAGS_SHADER_SAVE |
234 CTXT_FLAGS_GMEM_SHADOW |
235 CTXT_FLAGS_STATE_SHADOW);
236
Shubhraprakash Dasc9ec2662012-11-20 11:10:41 -0700237 drawctxt->flags |= CTXT_FLAGS_BEING_DESTROYED;
Shubhraprakash Dasfc2c9042012-08-15 04:11:55 -0700238
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700239 adreno_drawctxt_switch(adreno_dev, NULL, 0);
240 }
241
Tarun Karra5244cbd2012-09-20 13:27:20 -0700242 if (device->state != KGSL_STATE_HUNG)
243 adreno_idle(device);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700244
Rajeev Kulkarni27923382012-08-12 16:03:15 +0530245 if (adreno_is_a20x(adreno_dev) && adreno_dev->drawctxt_active)
246 kgsl_setstate(&device->mmu, adreno_dev->drawctxt_active->id,
247 KGSL_MMUFLAGS_PTUPDATE);
248
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700249 kgsl_sharedmem_free(&drawctxt->gpustate);
250 kgsl_sharedmem_free(&drawctxt->context_gmem_shadow.gmemshadow);
251
252 kfree(drawctxt);
253 context->devctxt = NULL;
254}
255
Jordan Crousea78c9172011-07-11 13:14:09 -0600256/**
257 * adreno_drawctxt_set_bin_base_offset - set bin base offset for the context
258 * @device - KGSL device that owns the context
259 * @context- Generic KGSL context container for the context
260 * @offset - Offset to set
261 *
262 * Set the bin base offset for A2XX devices. Not valid for A3XX devices.
263 */
264
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700265void adreno_drawctxt_set_bin_base_offset(struct kgsl_device *device,
266 struct kgsl_context *context,
267 unsigned int offset)
268{
269 struct adreno_context *drawctxt = context->devctxt;
270
271 if (drawctxt)
272 drawctxt->bin_base_offset = offset;
273}
274
Jordan Crousea78c9172011-07-11 13:14:09 -0600275/**
276 * adreno_drawctxt_switch - switch the current draw context
277 * @adreno_dev - The 3D device that owns the context
278 * @drawctxt - the 3D context to switch to
279 * @flags - Flags to accompany the switch (from user space)
280 *
281 * Switch the current draw context
282 */
283
284void adreno_drawctxt_switch(struct adreno_device *adreno_dev,
285 struct adreno_context *drawctxt,
286 unsigned int flags)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700287{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700288 struct kgsl_device *device = &adreno_dev->dev;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700289
290 if (drawctxt) {
291 if (flags & KGSL_CONTEXT_SAVE_GMEM)
292 /* Set the flag in context so that the save is done
293 * when this context is switched out. */
294 drawctxt->flags |= CTXT_FLAGS_GMEM_SAVE;
295 else
296 /* Remove GMEM saving flag from the context */
297 drawctxt->flags &= ~CTXT_FLAGS_GMEM_SAVE;
298 }
Jordan Crousea78c9172011-07-11 13:14:09 -0600299
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700300 /* already current? */
Shubhraprakash Das4624b552012-06-01 14:08:03 -0600301 if (adreno_dev->drawctxt_active == drawctxt) {
302 if (adreno_dev->gpudev->ctxt_draw_workaround &&
303 adreno_is_a225(adreno_dev))
304 adreno_dev->gpudev->ctxt_draw_workaround(
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600305 adreno_dev, drawctxt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700306 return;
Shubhraprakash Das4624b552012-06-01 14:08:03 -0600307 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700308
309 KGSL_CTXT_INFO(device, "from %p to %p flags %d\n",
310 adreno_dev->drawctxt_active, drawctxt, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700311
Jordan Crousea78c9172011-07-11 13:14:09 -0600312 /* Save the old context */
313 adreno_dev->gpudev->ctxt_save(adreno_dev, adreno_dev->drawctxt_active);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700314
Jordan Crousea78c9172011-07-11 13:14:09 -0600315 /* Set the new context */
Jordan Crousea78c9172011-07-11 13:14:09 -0600316 adreno_dev->gpudev->ctxt_restore(adreno_dev, drawctxt);
Shubhraprakash Dasb848f442012-04-26 15:53:46 -0600317 adreno_dev->drawctxt_active = drawctxt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700318}