blob: d0b2bd01f077fc7f3e28243b3b4c63f1062fe36e [file] [log] [blame]
Jordan Crouse72bb70b2013-05-28 17:03:52 -06001/* Copyright (c) 2002,2007-2013, 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>
Jordan Crouse72bb70b2013-05-28 17:03:52 -060015#include <linux/msm_kgsl.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070016
17#include "kgsl.h"
18#include "kgsl_sharedmem.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070019#include "adreno.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070020
Carter Cooper7e7f02e2012-02-15 09:36:31 -070021#define KGSL_INIT_REFTIMESTAMP 0x7FFFFFFF
22
Jordan Crouse0e0486f2011-07-28 08:37:58 -060023/* quad for copying GMEM to context shadow */
24#define QUAD_LEN 12
Jordan Crouseb4d31bd2012-02-01 22:11:12 -070025#define QUAD_RESTORE_LEN 14
Jordan Crouse0e0486f2011-07-28 08:37:58 -060026
27static unsigned int gmem_copy_quad[QUAD_LEN] = {
28 0x00000000, 0x00000000, 0x3f800000,
29 0x00000000, 0x00000000, 0x3f800000,
30 0x00000000, 0x00000000, 0x3f800000,
31 0x00000000, 0x00000000, 0x3f800000
32};
33
Jordan Crouseb4d31bd2012-02-01 22:11:12 -070034static unsigned int gmem_restore_quad[QUAD_RESTORE_LEN] = {
35 0x00000000, 0x3f800000, 0x3f800000,
36 0x00000000, 0x00000000, 0x00000000,
37 0x3f800000, 0x00000000, 0x00000000,
38 0x3f800000, 0x00000000, 0x00000000,
39 0x3f800000, 0x3f800000,
40};
41
Jordan Crouse0e0486f2011-07-28 08:37:58 -060042#define TEXCOORD_LEN 8
43
44static unsigned int gmem_copy_texcoord[TEXCOORD_LEN] = {
45 0x00000000, 0x3f800000,
46 0x3f800000, 0x3f800000,
47 0x00000000, 0x00000000,
48 0x3f800000, 0x00000000
49};
50
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070051/*
Jordan Crousea78c9172011-07-11 13:14:09 -060052 * Helper functions
53 * These are global helper functions used by the GPUs during context switch
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070054 */
55
Jordan Crousea78c9172011-07-11 13:14:09 -060056/**
57 * uint2float - convert a uint to IEEE754 single precision float
58 * @ uintval - value to convert
59 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070060
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070061unsigned int uint2float(unsigned int uintval)
62{
63 unsigned int exp, frac = 0;
64
65 if (uintval == 0)
66 return 0;
67
68 exp = ilog2(uintval);
69
70 /* Calculate fraction */
71 if (23 > exp)
72 frac = (uintval & (~(1 << exp))) << (23 - exp);
73
74 /* Exp is biased by 127 and shifted 23 bits */
75 exp = (exp + 127) << 23;
76
77 return exp | frac;
78}
79
Jordan Crouse0e0486f2011-07-28 08:37:58 -060080static void set_gmem_copy_quad(struct gmem_shadow_t *shadow)
81{
82 /* set vertex buffer values */
83 gmem_copy_quad[1] = uint2float(shadow->height);
84 gmem_copy_quad[3] = uint2float(shadow->width);
85 gmem_copy_quad[4] = uint2float(shadow->height);
86 gmem_copy_quad[9] = uint2float(shadow->width);
87
Jordan Crouseb4d31bd2012-02-01 22:11:12 -070088 gmem_restore_quad[5] = uint2float(shadow->height);
89 gmem_restore_quad[7] = uint2float(shadow->width);
Jordan Crouse0e0486f2011-07-28 08:37:58 -060090
91 memcpy(shadow->quad_vertices.hostptr, gmem_copy_quad, QUAD_LEN << 2);
Tarun Karra7e8e1cf2012-02-06 18:23:19 -080092 memcpy(shadow->quad_vertices_restore.hostptr, gmem_restore_quad,
Jordan Crouseb4d31bd2012-02-01 22:11:12 -070093 QUAD_RESTORE_LEN << 2);
Jordan Crouse0e0486f2011-07-28 08:37:58 -060094
95 memcpy(shadow->quad_texcoords.hostptr, gmem_copy_texcoord,
96 TEXCOORD_LEN << 2);
97}
98
99/**
100 * build_quad_vtxbuff - Create a quad for saving/restoring GMEM
101 * @ context - Pointer to the context being created
102 * @ shadow - Pointer to the GMEM shadow structure
103 * @ incmd - Pointer to pointer to the temporary command buffer
104 */
105
106/* quad for saving/restoring gmem */
107void build_quad_vtxbuff(struct adreno_context *drawctxt,
108 struct gmem_shadow_t *shadow, unsigned int **incmd)
109{
110 unsigned int *cmd = *incmd;
111
112 /* quad vertex buffer location (in GPU space) */
113 shadow->quad_vertices.hostptr = cmd;
114 shadow->quad_vertices.gpuaddr = virt2gpu(cmd, &drawctxt->gpustate);
115
116 cmd += QUAD_LEN;
117
Jordan Crouseb4d31bd2012-02-01 22:11:12 -0700118 /* Used by A3XX, but define for both to make the code easier */
119 shadow->quad_vertices_restore.hostptr = cmd;
120 shadow->quad_vertices_restore.gpuaddr =
121 virt2gpu(cmd, &drawctxt->gpustate);
122
123 cmd += QUAD_RESTORE_LEN;
124
Jordan Crouse0e0486f2011-07-28 08:37:58 -0600125 /* tex coord buffer location (in GPU space) */
126 shadow->quad_texcoords.hostptr = cmd;
127 shadow->quad_texcoords.gpuaddr = virt2gpu(cmd, &drawctxt->gpustate);
128
129 cmd += TEXCOORD_LEN;
130
131 set_gmem_copy_quad(shadow);
132 *incmd = cmd;
133}
134
Jordan Crousea78c9172011-07-11 13:14:09 -0600135/**
136 * adreno_drawctxt_create - create a new adreno draw context
137 * @device - KGSL device to create the context on
138 * @pagetable - Pagetable for the context
139 * @context- Generic KGSL context structure
140 * @flags - flags for the context (passed from user space)
141 *
142 * Create a new draw context for the 3D core. Return 0 on success,
143 * or error code on failure.
144 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700145int adreno_drawctxt_create(struct kgsl_device *device,
146 struct kgsl_pagetable *pagetable,
Jordan Crouse72bb70b2013-05-28 17:03:52 -0600147 struct kgsl_context *context, uint32_t *flags)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700148{
149 struct adreno_context *drawctxt;
150 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
Carter Cooper7ffaba62012-05-24 13:59:53 -0600151 struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700152 int ret;
153
154 drawctxt = kzalloc(sizeof(struct adreno_context), GFP_KERNEL);
155
156 if (drawctxt == NULL)
157 return -ENOMEM;
158
Tarun Karra5bea9c62013-01-27 17:39:17 -0800159 drawctxt->pid = task_pid_nr(current);
160 strlcpy(drawctxt->pid_name, current->comm, TASK_COMM_LEN);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700161 drawctxt->pagetable = pagetable;
162 drawctxt->bin_base_offset = 0;
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700163 drawctxt->id = context->id;
Carter Cooper7ffaba62012-05-24 13:59:53 -0600164 rb->timestamp[context->id] = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700165
Jordan Crouse72bb70b2013-05-28 17:03:52 -0600166 *flags &= (KGSL_CONTEXT_PREAMBLE |
167 KGSL_CONTEXT_NO_GMEM_ALLOC |
168 KGSL_CONTEXT_PER_CONTEXT_TS |
169 KGSL_CONTEXT_USER_GENERATED_TS |
170 KGSL_CONTEXT_TYPE_MASK);
171
172 if (*flags & KGSL_CONTEXT_PREAMBLE)
Vijay Krishnamoorthybef66932012-01-24 09:32:05 -0700173 drawctxt->flags |= CTXT_FLAGS_PREAMBLE;
Jordan Crousea78c9172011-07-11 13:14:09 -0600174
Jordan Crouse72bb70b2013-05-28 17:03:52 -0600175 if (*flags & KGSL_CONTEXT_NO_GMEM_ALLOC)
Vijay Krishnamoorthybef66932012-01-24 09:32:05 -0700176 drawctxt->flags |= CTXT_FLAGS_NOGMEMALLOC;
177
Jordan Crouse72bb70b2013-05-28 17:03:52 -0600178 if (*flags & KGSL_CONTEXT_PER_CONTEXT_TS)
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700179 drawctxt->flags |= CTXT_FLAGS_PER_CONTEXT_TS;
180
Jordan Crouse72bb70b2013-05-28 17:03:52 -0600181 if (*flags & KGSL_CONTEXT_USER_GENERATED_TS) {
182 if (!(*flags & KGSL_CONTEXT_PER_CONTEXT_TS)) {
Vijay Krishnamoorthye80c3462012-08-27 14:07:32 -0700183 ret = -EINVAL;
184 goto err;
185 }
186 drawctxt->flags |= CTXT_FLAGS_USER_GENERATED_TS;
187 }
188
Jordan Crouse72bb70b2013-05-28 17:03:52 -0600189 if (*flags & KGSL_CONTEXT_NO_FAULT_TOLERANCE)
Tarun Karra83297222013-02-05 19:45:49 -0800190 drawctxt->flags |= CTXT_FLAGS_NO_FAULT_TOLERANCE;
191
Jordan Crouse72bb70b2013-05-28 17:03:52 -0600192 drawctxt->type =
193 (*flags & KGSL_CONTEXT_TYPE_MASK) >> KGSL_CONTEXT_TYPE_SHIFT;
194
Vijay Krishnamoorthybef66932012-01-24 09:32:05 -0700195 ret = adreno_dev->gpudev->ctxt_create(adreno_dev, drawctxt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700196 if (ret)
197 goto err;
198
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700199 kgsl_sharedmem_writel(&device->memstore,
200 KGSL_MEMSTORE_OFFSET(drawctxt->id, ref_wait_ts),
201 KGSL_INIT_REFTIMESTAMP);
Carter Cooper7ffaba62012-05-24 13:59:53 -0600202 kgsl_sharedmem_writel(&device->memstore,
203 KGSL_MEMSTORE_OFFSET(drawctxt->id, ts_cmp_enable), 0);
204 kgsl_sharedmem_writel(&device->memstore,
205 KGSL_MEMSTORE_OFFSET(drawctxt->id, soptimestamp), 0);
206 kgsl_sharedmem_writel(&device->memstore,
207 KGSL_MEMSTORE_OFFSET(drawctxt->id, eoptimestamp), 0);
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700208
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700209 context->devctxt = drawctxt;
210 return 0;
211err:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700212 kfree(drawctxt);
213 return ret;
214}
215
Jordan Crousea78c9172011-07-11 13:14:09 -0600216/**
217 * adreno_drawctxt_destroy - destroy a draw context
218 * @device - KGSL device that owns the context
219 * @context- Generic KGSL context container for the context
220 *
221 * Destroy an existing context. Return 0 on success or error
222 * code on failure.
223 */
224
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700225/* destroy a drawing context */
226
227void adreno_drawctxt_destroy(struct kgsl_device *device,
228 struct kgsl_context *context)
229{
230 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700231 struct adreno_context *drawctxt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700232
Jordan Crouse87239682012-06-19 13:08:22 -0600233 if (context == NULL || context->devctxt == NULL)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700234 return;
235
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700236 drawctxt = context->devctxt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700237 /* deactivate context */
238 if (adreno_dev->drawctxt_active == drawctxt) {
239 /* no need to save GMEM or shader, the context is
240 * being destroyed.
241 */
242 drawctxt->flags &= ~(CTXT_FLAGS_GMEM_SAVE |
243 CTXT_FLAGS_SHADER_SAVE |
244 CTXT_FLAGS_GMEM_SHADOW |
245 CTXT_FLAGS_STATE_SHADOW);
246
Shubhraprakash Dasc9ec2662012-11-20 11:10:41 -0700247 drawctxt->flags |= CTXT_FLAGS_BEING_DESTROYED;
Shubhraprakash Dasfc2c9042012-08-15 04:11:55 -0700248
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700249 adreno_drawctxt_switch(adreno_dev, NULL, 0);
250 }
251
Tarun Karra5244cbd2012-09-20 13:27:20 -0700252 if (device->state != KGSL_STATE_HUNG)
253 adreno_idle(device);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700254
Rajeev Kulkarni27923382012-08-12 16:03:15 +0530255 if (adreno_is_a20x(adreno_dev) && adreno_dev->drawctxt_active)
256 kgsl_setstate(&device->mmu, adreno_dev->drawctxt_active->id,
257 KGSL_MMUFLAGS_PTUPDATE);
258
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700259 kgsl_sharedmem_free(&drawctxt->gpustate);
260 kgsl_sharedmem_free(&drawctxt->context_gmem_shadow.gmemshadow);
261
262 kfree(drawctxt);
263 context->devctxt = NULL;
264}
265
Jordan Crousea78c9172011-07-11 13:14:09 -0600266/**
267 * adreno_drawctxt_set_bin_base_offset - set bin base offset for the context
268 * @device - KGSL device that owns the context
269 * @context- Generic KGSL context container for the context
270 * @offset - Offset to set
271 *
272 * Set the bin base offset for A2XX devices. Not valid for A3XX devices.
273 */
274
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700275void adreno_drawctxt_set_bin_base_offset(struct kgsl_device *device,
276 struct kgsl_context *context,
277 unsigned int offset)
278{
279 struct adreno_context *drawctxt = context->devctxt;
280
281 if (drawctxt)
282 drawctxt->bin_base_offset = offset;
283}
284
Jordan Crousea78c9172011-07-11 13:14:09 -0600285/**
286 * adreno_drawctxt_switch - switch the current draw context
287 * @adreno_dev - The 3D device that owns the context
288 * @drawctxt - the 3D context to switch to
289 * @flags - Flags to accompany the switch (from user space)
290 *
291 * Switch the current draw context
292 */
293
294void adreno_drawctxt_switch(struct adreno_device *adreno_dev,
295 struct adreno_context *drawctxt,
296 unsigned int flags)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700297{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700298 struct kgsl_device *device = &adreno_dev->dev;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700299
300 if (drawctxt) {
301 if (flags & KGSL_CONTEXT_SAVE_GMEM)
302 /* Set the flag in context so that the save is done
303 * when this context is switched out. */
304 drawctxt->flags |= CTXT_FLAGS_GMEM_SAVE;
305 else
306 /* Remove GMEM saving flag from the context */
307 drawctxt->flags &= ~CTXT_FLAGS_GMEM_SAVE;
308 }
Jordan Crousea78c9172011-07-11 13:14:09 -0600309
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700310 /* already current? */
Shubhraprakash Das4624b552012-06-01 14:08:03 -0600311 if (adreno_dev->drawctxt_active == drawctxt) {
312 if (adreno_dev->gpudev->ctxt_draw_workaround &&
313 adreno_is_a225(adreno_dev))
314 adreno_dev->gpudev->ctxt_draw_workaround(
Shubhraprakash Dasb2abc452012-06-08 16:33:03 -0600315 adreno_dev, drawctxt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700316 return;
Shubhraprakash Das4624b552012-06-01 14:08:03 -0600317 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700318
319 KGSL_CTXT_INFO(device, "from %p to %p flags %d\n",
320 adreno_dev->drawctxt_active, drawctxt, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700321
Jordan Crousea78c9172011-07-11 13:14:09 -0600322 /* Save the old context */
323 adreno_dev->gpudev->ctxt_save(adreno_dev, adreno_dev->drawctxt_active);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700324
Jordan Crousea78c9172011-07-11 13:14:09 -0600325 /* Set the new context */
Jordan Crousea78c9172011-07-11 13:14:09 -0600326 adreno_dev->gpudev->ctxt_restore(adreno_dev, drawctxt);
Shubhraprakash Dasb848f442012-04-26 15:53:46 -0600327 adreno_dev->drawctxt_active = drawctxt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700328}