OSDN Git Service

Radeon: restructure PLL data
[android-x86/external-libdrm.git] / shared-core / radeon_cs.c
1 /*
2  * Copyright 2008 Jerome Glisse.
3  * All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  *
24  * Authors:
25  *    Jerome Glisse <glisse@freedesktop.org>
26  */
27 #include "drmP.h"
28 #include "radeon_drm.h"
29 #include "radeon_drv.h"
30 #include "r300_reg.h"
31
32 int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *fpriv)
33 {
34         struct drm_radeon_private *dev_priv = dev->dev_private;
35         struct drm_radeon_cs *cs = data;
36         uint32_t *packets = NULL;
37         uint32_t cs_id;
38         uint32_t card_offset;
39         void *ib = NULL;
40         long size;
41         int r;
42         RING_LOCALS;
43
44         /* set command stream id to 0 which is fake id */
45         cs_id = 0;
46         DRM_COPY_TO_USER(&cs->cs_id, &cs_id, sizeof(uint32_t));
47
48         if (dev_priv == NULL) {
49                 DRM_ERROR("called with no initialization\n");
50                 return -EINVAL;
51         }
52         if (!cs->dwords) {
53                 return 0;
54         }
55         /* limit cs to 64K ib */
56         if (cs->dwords > (16 * 1024)) {
57                 return -EINVAL;
58         }
59         /* copy cs from userspace maybe we should copy into ib to save
60          * one copy but ib will be mapped wc so not good for cmd checking
61          * somethings worth testing i guess (Jerome)
62          */
63         size = cs->dwords * sizeof(uint32_t);
64         packets = drm_alloc(size, DRM_MEM_DRIVER);
65         if (packets == NULL) {
66                 return -ENOMEM;
67         }
68         if (DRM_COPY_FROM_USER(packets, (void __user *)(unsigned long)cs->packets, size)) {
69                 r = -EFAULT;
70                 goto out;
71         }
72         /* get ib */
73         r = dev_priv->cs.ib_get(dev, &ib, cs->dwords, &card_offset);
74         if (r) {
75                 goto out;
76         }
77
78         /* now parse command stream */
79         r = dev_priv->cs.parse(dev, fpriv, ib, packets, cs->dwords);
80         if (r) {
81                 goto out;
82         }
83
84         BEGIN_RING(4);
85         OUT_RING(CP_PACKET0(RADEON_CP_IB_BASE, 1));
86         OUT_RING(card_offset);
87         OUT_RING(cs->dwords);
88         OUT_RING(CP_PACKET2());
89         ADVANCE_RING();
90
91         /* emit cs id sequence */
92         dev_priv->cs.id_emit(dev, &cs_id);
93         COMMIT_RING();
94
95         DRM_COPY_TO_USER(&cs->cs_id, &cs_id, sizeof(uint32_t));
96 out:
97         dev_priv->cs.ib_free(dev, ib, cs->dwords);
98         drm_free(packets, size, DRM_MEM_DRIVER);
99         return r;
100 }
101
102 /* for non-mm */
103 static int radeon_nomm_relocate(struct drm_device *dev, struct drm_file *file_priv, uint32_t *reloc, uint32_t *offset)
104 {
105         *offset = reloc[1];
106         return 0;
107 }
108 #define RELOC_SIZE 2
109 #define RADEON_2D_OFFSET_MASK 0x3fffff
110
111 static __inline__ int radeon_cs_relocate_packet0(struct drm_device *dev, struct drm_file *file_priv,
112                                                  uint32_t *packets, uint32_t offset_dw)
113 {
114         drm_radeon_private_t *dev_priv = dev->dev_private;
115         uint32_t hdr = packets[offset_dw];
116         uint32_t reg = (hdr & R300_CP_PACKET0_REG_MASK) << 2;
117         uint32_t val = packets[offset_dw + 1];
118         uint32_t packet3_hdr = packets[offset_dw+2];
119         uint32_t tmp, offset;
120         int ret;
121
122         /* this is too strict we may want to expand the length in the future and have
123          old kernels ignore it. */ 
124         if (packet3_hdr != (RADEON_CP_PACKET3 | RADEON_CP_NOP | (RELOC_SIZE << 16))) {
125                 DRM_ERROR("Packet 3 was %x should have been %x\n", packet3_hdr, RADEON_CP_PACKET3 | RADEON_CP_NOP | (RELOC_SIZE << 16));
126                 return -EINVAL;
127         }
128         
129         switch(reg) {
130         case RADEON_DST_PITCH_OFFSET:
131         case RADEON_SRC_PITCH_OFFSET:
132                 /* pass in the start of the reloc */
133                 ret = dev_priv->cs.relocate(dev, file_priv, packets + offset_dw + 2, &offset);
134                 if (ret)
135                         return ret;
136                 tmp = (val & RADEON_2D_OFFSET_MASK) << 10;
137                 val &= ~RADEON_2D_OFFSET_MASK;
138                 offset += tmp;
139                 offset >>= 10;
140                 val |= offset;
141                 break;
142         case R300_RB3D_COLOROFFSET0:
143         case R300_ZB_DEPTHOFFSET:
144         case R300_TX_OFFSET_0:
145         case R300_TX_OFFSET_0+4:
146                 ret = dev_priv->cs.relocate(dev, file_priv, packets + offset_dw + 2, &offset);
147                 if (ret)
148                         return ret;
149
150                 offset &= 0xffffffe0;
151                 val += offset;
152                 break;
153         default:
154                 break;
155         }
156
157         packets[offset_dw + 1] = val;
158         return 0;
159 }
160
161 static int radeon_cs_relocate_packet3(struct drm_device *dev, struct drm_file *file_priv,
162                                       uint32_t *packets, uint32_t offset_dw)
163 {
164         drm_radeon_private_t *dev_priv = dev->dev_private;
165         uint32_t hdr = packets[offset_dw];
166         int num_dw = (hdr & RADEON_CP_PACKET_COUNT_MASK) >> 16;
167         uint32_t reg = hdr & 0xff00;
168         uint32_t offset, val, tmp;
169         int ret;
170
171         switch(reg) {
172         case RADEON_CNTL_HOSTDATA_BLT:
173         {
174                 val = packets[offset_dw + 2];
175                 ret = dev_priv->cs.relocate(dev, file_priv, packets + offset_dw + num_dw + 2, &offset);
176                 if (ret)
177                         return ret;
178
179                 tmp = (val & RADEON_2D_OFFSET_MASK) << 10;
180                 val &= ~RADEON_2D_OFFSET_MASK;
181                 offset += tmp;
182                 offset >>= 10;
183                 val |= offset;
184
185                 packets[offset_dw + 2] = val;
186         }
187         default:
188                 return -EINVAL;
189         }
190         return 0;
191 }
192
193 static __inline__ int radeon_cs_check_offset(struct drm_device *dev,
194                                              uint32_t reg, uint32_t val)
195 {
196         uint32_t offset;
197
198         switch(reg) {
199         case RADEON_DST_PITCH_OFFSET:
200         case RADEON_SRC_PITCH_OFFSET:
201                 offset = val & ((1 << 22) - 1);
202                 offset <<= 10;
203                 break;
204         case R300_RB3D_COLOROFFSET0:
205         case R300_ZB_DEPTHOFFSET:
206                 offset = val;
207                 break;
208         case R300_TX_OFFSET_0:
209         case R300_TX_OFFSET_0+4:
210                 offset = val & 0xffffffe0;
211                 break;
212         }
213         
214         return 0;
215 }
216
217 int radeon_cs_packet0(struct drm_device *dev, struct drm_file *file_priv,
218                       uint32_t *packets, uint32_t offset_dw)
219 {
220         drm_radeon_private_t *dev_priv = dev->dev_private;
221         uint32_t hdr = packets[offset_dw];
222         int num_dw = ((hdr & RADEON_CP_PACKET_COUNT_MASK) >> 16) + 2;
223         int need_reloc = 0;
224         int reg = (hdr & R300_CP_PACKET0_REG_MASK) << 2;
225         int count_dw = 1;
226         int ret;
227
228         while (count_dw < num_dw) {
229                 /* need to have something like the r300 validation here - 
230                    list of allowed registers */
231                 int flags;
232
233                 ret = r300_check_range(reg, 1);
234                 switch(ret) {
235                 case -1:
236                         DRM_ERROR("Illegal register %x\n", reg);
237                         break;
238                 case 0:
239                         break;
240                 case 1:
241                         flags = r300_get_reg_flags(reg);
242                         if (flags == MARK_CHECK_OFFSET) {
243                                 if (num_dw > 2) {
244                                         DRM_ERROR("Cannot relocate inside type stream of reg0 packets\n");
245                                         return -EINVAL;
246                                 }
247
248                                 ret = radeon_cs_relocate_packet0(dev, file_priv, packets, offset_dw);
249                                 if (ret)
250                                         return ret;
251                                 DRM_DEBUG("need to relocate %x %d\n", reg, flags);
252                                 /* okay it should be followed by a NOP */
253                         } else if (flags == MARK_CHECK_SCISSOR) {
254                                 DRM_DEBUG("need to validate scissor %x %d\n", reg, flags);
255                         } else {
256                                 DRM_DEBUG("illegal register %x %d\n", reg, flags);
257                                 return -EINVAL;
258                         }
259                         break;
260                 }
261                 count_dw++;
262                 reg += 4;
263         }
264         return 0;
265 }
266
267 int radeon_cs_parse(struct drm_device *dev, struct drm_file *file_priv,
268                     void *ib, uint32_t *packets, uint32_t dwords)
269 {
270         drm_radeon_private_t *dev_priv = dev->dev_private;
271         volatile int rb;
272         int size_dw = dwords;
273         /* scan the packet for various things */
274         int count_dw = 0;
275         int ret = 0;
276
277         while (count_dw < size_dw && ret == 0) {
278                 int hdr = packets[count_dw];
279                 int num_dw = (hdr & RADEON_CP_PACKET_COUNT_MASK) >> 16;
280                 int reg;
281
282                 switch (hdr & RADEON_CP_PACKET_MASK) {
283                 case RADEON_CP_PACKET0:
284                         ret = radeon_cs_packet0(dev, file_priv, packets, count_dw);
285                         break;
286                 case RADEON_CP_PACKET1:
287                 case RADEON_CP_PACKET2:
288                         reg = hdr & RADEON_CP_PACKET0_REG_MASK;
289                         DRM_DEBUG("Packet 1/2: %d  %x\n", num_dw, reg);
290                         break;
291
292                 case RADEON_CP_PACKET3:
293                         reg = hdr & 0xff00;
294                         
295                         switch(reg) {
296                         case RADEON_CNTL_HOSTDATA_BLT:
297                                 radeon_cs_relocate_packet3(dev, file_priv, packets, count_dw);
298                                 break;
299
300                         case RADEON_CNTL_BITBLT_MULTI:
301                         case RADEON_3D_LOAD_VBPNTR:     /* load vertex array pointers */
302                         case RADEON_CP_INDX_BUFFER:
303                                 DRM_ERROR("need relocate packet 3 for %x\n", reg);
304                                 break;
305
306                         case RADEON_CP_3D_DRAW_IMMD_2:  /* triggers drawing using in-packet vertex data */
307                         case RADEON_CP_3D_DRAW_VBUF_2:  /* triggers drawing of vertex buffers setup elsewhere */
308                         case RADEON_CP_3D_DRAW_INDX_2:  /* triggers drawing using indices to vertex buffer */
309                         case RADEON_WAIT_FOR_IDLE:
310                         case RADEON_CP_NOP:
311                                 break;
312                         default:
313                                 DRM_ERROR("unknown packet 3 %x\n", reg);
314                                 ret = -EINVAL;
315                         }
316                         break;
317                 }
318
319                 count_dw += num_dw+2;
320         }
321
322         if (ret)
323                 return ret;
324              
325
326         /* copy the packet into the IB */
327         memcpy(ib, packets, dwords * sizeof(uint32_t));
328
329         /* read back last byte to flush WC buffers */
330         rb = readl((ib + (dwords-1) * sizeof(uint32_t)));
331
332         return 0;
333 }
334
335 uint32_t radeon_cs_id_get(struct drm_radeon_private *radeon)
336 {
337         /* FIXME: protect with a spinlock */
338         /* FIXME: check if wrap affect last reported wrap & sequence */
339         radeon->cs.id_scnt = (radeon->cs.id_scnt + 1) & 0x00FFFFFF;
340         if (!radeon->cs.id_scnt) {
341                 /* increment wrap counter */
342                 radeon->cs.id_wcnt += 0x01000000;
343                 /* valid sequence counter start at 1 */
344                 radeon->cs.id_scnt = 1;
345         }
346         return (radeon->cs.id_scnt | radeon->cs.id_wcnt);
347 }
348
349 void r100_cs_id_emit(struct drm_device *dev, uint32_t *id)
350 {
351         drm_radeon_private_t *dev_priv = dev->dev_private;
352         RING_LOCALS;
353
354         /* ISYNC_CNTL should have CPSCRACTH bit set */
355         *id = radeon_cs_id_get(dev_priv);
356         /* emit id in SCRATCH4 (not used yet in old drm) */
357         BEGIN_RING(2);
358         OUT_RING(CP_PACKET0(RADEON_SCRATCH_REG4, 0));
359         OUT_RING(*id);
360         ADVANCE_RING(); 
361 }
362
363 void r300_cs_id_emit(struct drm_device *dev, uint32_t *id)
364 {
365         drm_radeon_private_t *dev_priv = dev->dev_private;
366         RING_LOCALS;
367
368         /* ISYNC_CNTL should not have CPSCRACTH bit set */
369         *id = radeon_cs_id_get(dev_priv);
370         /* emit id in SCRATCH6 */
371         BEGIN_RING(8);
372         OUT_RING(CP_PACKET0(R300_CP_RESYNC_ADDR, 0));
373         OUT_RING(6);
374         OUT_RING(CP_PACKET0(R300_CP_RESYNC_DATA, 0));
375         OUT_RING(*id);
376         OUT_RING(CP_PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0));
377         OUT_RING(R300_RB3D_DC_FINISH);
378         RADEON_WAIT_UNTIL_3D_IDLE();
379         ADVANCE_RING(); 
380 }
381
382 uint32_t r100_cs_id_last_get(struct drm_device *dev)
383 {
384         drm_radeon_private_t *dev_priv = dev->dev_private;
385
386         return RADEON_READ(RADEON_SCRATCH_REG4);
387 }
388
389 uint32_t r300_cs_id_last_get(struct drm_device *dev)
390 {
391         drm_radeon_private_t *dev_priv = dev->dev_private;
392
393         return RADEON_READ(RADEON_SCRATCH_REG6);
394 }
395
396 int radeon_cs_init(struct drm_device *dev)
397 {
398         drm_radeon_private_t *dev_priv = dev->dev_private;
399
400         if (dev_priv->chip_family < CHIP_RV280) {
401                 dev_priv->cs.id_emit = r100_cs_id_emit;
402                 dev_priv->cs.id_last_get = r100_cs_id_last_get;
403         } else if (dev_priv->chip_family < CHIP_R600) {
404                 dev_priv->cs.id_emit = r300_cs_id_emit;
405                 dev_priv->cs.id_last_get = r300_cs_id_last_get;
406         }
407
408         dev_priv->cs.parse = radeon_cs_parse;
409         /* ib get depends on memory manager or not so memory manager */
410         dev_priv->cs.relocate = radeon_nomm_relocate;
411         return 0;
412 }