blob: b7b0ea46007a38e0d65e7eea09791dc468bf8a43 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2002,2007-2011, Code Aurora Forum. All rights reserved.
2 *
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
Jordan Crouse0e0486f2011-07-28 08:37:58 -060020/* quad for copying GMEM to context shadow */
21#define QUAD_LEN 12
22
23static unsigned int gmem_copy_quad[QUAD_LEN] = {
24 0x00000000, 0x00000000, 0x3f800000,
25 0x00000000, 0x00000000, 0x3f800000,
26 0x00000000, 0x00000000, 0x3f800000,
27 0x00000000, 0x00000000, 0x3f800000
28};
29
30#define TEXCOORD_LEN 8
31
32static unsigned int gmem_copy_texcoord[TEXCOORD_LEN] = {
33 0x00000000, 0x3f800000,
34 0x3f800000, 0x3f800000,
35 0x00000000, 0x00000000,
36 0x3f800000, 0x00000000
37};
38
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070039/*
Jordan Crousea78c9172011-07-11 13:14:09 -060040 * Helper functions
41 * These are global helper functions used by the GPUs during context switch
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070042 */
43
Jordan Crousea78c9172011-07-11 13:14:09 -060044/**
45 * uint2float - convert a uint to IEEE754 single precision float
46 * @ uintval - value to convert
47 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070048
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070049unsigned int uint2float(unsigned int uintval)
50{
51 unsigned int exp, frac = 0;
52
53 if (uintval == 0)
54 return 0;
55
56 exp = ilog2(uintval);
57
58 /* Calculate fraction */
59 if (23 > exp)
60 frac = (uintval & (~(1 << exp))) << (23 - exp);
61
62 /* Exp is biased by 127 and shifted 23 bits */
63 exp = (exp + 127) << 23;
64
65 return exp | frac;
66}
67
Jordan Crouse0e0486f2011-07-28 08:37:58 -060068static void set_gmem_copy_quad(struct gmem_shadow_t *shadow)
69{
70 /* set vertex buffer values */
71 gmem_copy_quad[1] = uint2float(shadow->height);
72 gmem_copy_quad[3] = uint2float(shadow->width);
73 gmem_copy_quad[4] = uint2float(shadow->height);
74 gmem_copy_quad[9] = uint2float(shadow->width);
75
76 gmem_copy_quad[0] = 0;
77 gmem_copy_quad[6] = 0;
78 gmem_copy_quad[7] = 0;
79 gmem_copy_quad[10] = 0;
80
81 memcpy(shadow->quad_vertices.hostptr, gmem_copy_quad, QUAD_LEN << 2);
82
83 memcpy(shadow->quad_texcoords.hostptr, gmem_copy_texcoord,
84 TEXCOORD_LEN << 2);
85}
86
87/**
88 * build_quad_vtxbuff - Create a quad for saving/restoring GMEM
89 * @ context - Pointer to the context being created
90 * @ shadow - Pointer to the GMEM shadow structure
91 * @ incmd - Pointer to pointer to the temporary command buffer
92 */
93
94/* quad for saving/restoring gmem */
95void build_quad_vtxbuff(struct adreno_context *drawctxt,
96 struct gmem_shadow_t *shadow, unsigned int **incmd)
97{
98 unsigned int *cmd = *incmd;
99
100 /* quad vertex buffer location (in GPU space) */
101 shadow->quad_vertices.hostptr = cmd;
102 shadow->quad_vertices.gpuaddr = virt2gpu(cmd, &drawctxt->gpustate);
103
104 cmd += QUAD_LEN;
105
106 /* tex coord buffer location (in GPU space) */
107 shadow->quad_texcoords.hostptr = cmd;
108 shadow->quad_texcoords.gpuaddr = virt2gpu(cmd, &drawctxt->gpustate);
109
110 cmd += TEXCOORD_LEN;
111
112 set_gmem_copy_quad(shadow);
113 *incmd = cmd;
114}
115
Jordan Crousea78c9172011-07-11 13:14:09 -0600116/**
117 * adreno_drawctxt_create - create a new adreno draw context
118 * @device - KGSL device to create the context on
119 * @pagetable - Pagetable for the context
120 * @context- Generic KGSL context structure
121 * @flags - flags for the context (passed from user space)
122 *
123 * Create a new draw context for the 3D core. Return 0 on success,
124 * or error code on failure.
125 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700126int adreno_drawctxt_create(struct kgsl_device *device,
127 struct kgsl_pagetable *pagetable,
128 struct kgsl_context *context, uint32_t flags)
129{
130 struct adreno_context *drawctxt;
131 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700132 int ret;
133
134 drawctxt = kzalloc(sizeof(struct adreno_context), GFP_KERNEL);
135
136 if (drawctxt == NULL)
137 return -ENOMEM;
138
139 drawctxt->pagetable = pagetable;
140 drawctxt->bin_base_offset = 0;
141
Jordan Crousea78c9172011-07-11 13:14:09 -0600142 /* FIXME: Deal with preambles */
143
144 ret = adreno_dev->gpudev->ctxt_gpustate_shadow(adreno_dev, drawctxt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700145 if (ret)
146 goto err;
147
148 /* Save the shader instruction memory on context switching */
149 drawctxt->flags |= CTXT_FLAGS_SHADER_SAVE;
150
151 if (!(flags & KGSL_CONTEXT_NO_GMEM_ALLOC)) {
152 /* create gmem shadow */
Jordan Crousea78c9172011-07-11 13:14:09 -0600153 ret = adreno_dev->gpudev->ctxt_gmem_shadow(adreno_dev,
154 drawctxt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700155 if (ret != 0)
156 goto err;
157 }
158
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700159 context->devctxt = drawctxt;
160 return 0;
161err:
162 kgsl_sharedmem_free(&drawctxt->gpustate);
163 kfree(drawctxt);
164 return ret;
165}
166
Jordan Crousea78c9172011-07-11 13:14:09 -0600167/**
168 * adreno_drawctxt_destroy - destroy a draw context
169 * @device - KGSL device that owns the context
170 * @context- Generic KGSL context container for the context
171 *
172 * Destroy an existing context. Return 0 on success or error
173 * code on failure.
174 */
175
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700176/* destroy a drawing context */
177
178void adreno_drawctxt_destroy(struct kgsl_device *device,
179 struct kgsl_context *context)
180{
181 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
182 struct adreno_context *drawctxt = context->devctxt;
183
184 if (drawctxt == NULL)
185 return;
186
187 /* deactivate context */
188 if (adreno_dev->drawctxt_active == drawctxt) {
189 /* no need to save GMEM or shader, the context is
190 * being destroyed.
191 */
192 drawctxt->flags &= ~(CTXT_FLAGS_GMEM_SAVE |
193 CTXT_FLAGS_SHADER_SAVE |
194 CTXT_FLAGS_GMEM_SHADOW |
195 CTXT_FLAGS_STATE_SHADOW);
196
197 adreno_drawctxt_switch(adreno_dev, NULL, 0);
198 }
199
200 adreno_idle(device, KGSL_TIMEOUT_DEFAULT);
201
202 kgsl_sharedmem_free(&drawctxt->gpustate);
203 kgsl_sharedmem_free(&drawctxt->context_gmem_shadow.gmemshadow);
204
205 kfree(drawctxt);
206 context->devctxt = NULL;
207}
208
Jordan Crousea78c9172011-07-11 13:14:09 -0600209/**
210 * adreno_drawctxt_set_bin_base_offset - set bin base offset for the context
211 * @device - KGSL device that owns the context
212 * @context- Generic KGSL context container for the context
213 * @offset - Offset to set
214 *
215 * Set the bin base offset for A2XX devices. Not valid for A3XX devices.
216 */
217
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700218void adreno_drawctxt_set_bin_base_offset(struct kgsl_device *device,
219 struct kgsl_context *context,
220 unsigned int offset)
221{
222 struct adreno_context *drawctxt = context->devctxt;
223
224 if (drawctxt)
225 drawctxt->bin_base_offset = offset;
226}
227
Jordan Crousea78c9172011-07-11 13:14:09 -0600228/**
229 * adreno_drawctxt_switch - switch the current draw context
230 * @adreno_dev - The 3D device that owns the context
231 * @drawctxt - the 3D context to switch to
232 * @flags - Flags to accompany the switch (from user space)
233 *
234 * Switch the current draw context
235 */
236
237void adreno_drawctxt_switch(struct adreno_device *adreno_dev,
238 struct adreno_context *drawctxt,
239 unsigned int flags)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700240{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700241 struct kgsl_device *device = &adreno_dev->dev;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700242
243 if (drawctxt) {
244 if (flags & KGSL_CONTEXT_SAVE_GMEM)
245 /* Set the flag in context so that the save is done
246 * when this context is switched out. */
247 drawctxt->flags |= CTXT_FLAGS_GMEM_SAVE;
248 else
249 /* Remove GMEM saving flag from the context */
250 drawctxt->flags &= ~CTXT_FLAGS_GMEM_SAVE;
251 }
Jordan Crousea78c9172011-07-11 13:14:09 -0600252
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700253 /* already current? */
Jordan Crousea78c9172011-07-11 13:14:09 -0600254 if (adreno_dev->drawctxt_active == drawctxt)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700255 return;
256
257 KGSL_CTXT_INFO(device, "from %p to %p flags %d\n",
258 adreno_dev->drawctxt_active, drawctxt, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700259
Jordan Crousea78c9172011-07-11 13:14:09 -0600260 /* Save the old context */
261 adreno_dev->gpudev->ctxt_save(adreno_dev, adreno_dev->drawctxt_active);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700262
Jordan Crousea78c9172011-07-11 13:14:09 -0600263 /* Set the new context */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700264 adreno_dev->drawctxt_active = drawctxt;
Jordan Crousea78c9172011-07-11 13:14:09 -0600265 adreno_dev->gpudev->ctxt_restore(adreno_dev, drawctxt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700266}