OSDN Git Service

drm: convert drawable handling to use Linux idr
[android-x86/external-libdrm.git] / shared-core / mach64_state.c
1 /* mach64_state.c -- State support for mach64 (Rage Pro) driver -*- linux-c -*-
2  * Created: Sun Dec 03 19:20:26 2000 by gareth@valinux.com
3  */
4 /*
5  * Copyright 2000 Gareth Hughes
6  * Copyright 2002-2003 Leif Delgass
7  * All Rights Reserved.
8  *
9  * Permission is hereby granted, free of charge, to any person obtaining a
10  * copy of this software and associated documentation files (the "Software"),
11  * to deal in the Software without restriction, including without limitation
12  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13  * and/or sell copies of the Software, and to permit persons to whom the
14  * Software is furnished to do so, subject to the following conditions:
15  *
16  * The above copyright notice and this permission notice (including the next
17  * paragraph) shall be included in all copies or substantial portions of the
18  * Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
23  * THE COPYRIGHT OWNER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
24  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26  *
27  * Authors:
28  *    Gareth Hughes <gareth@valinux.com>
29  *    Leif Delgass <ldelgass@retinalburn.net>
30  *    Jos�Fonseca <j_r_fonseca@yahoo.co.uk>
31  */
32
33 #include "drmP.h"
34 #include "drm.h"
35 #include "mach64_drm.h"
36 #include "mach64_drv.h"
37
38 /* Interface history:
39  *
40  * 1.0 - Initial mach64 DRM
41  *
42  */
43 drm_ioctl_desc_t mach64_ioctls[] = {
44         [DRM_IOCTL_NR(DRM_MACH64_INIT)] = {mach64_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
45         [DRM_IOCTL_NR(DRM_MACH64_CLEAR)] = {mach64_dma_clear, DRM_AUTH},
46         [DRM_IOCTL_NR(DRM_MACH64_SWAP)] = {mach64_dma_swap, DRM_AUTH},
47         [DRM_IOCTL_NR(DRM_MACH64_IDLE)] = {mach64_dma_idle, DRM_AUTH},
48         [DRM_IOCTL_NR(DRM_MACH64_RESET)] = {mach64_engine_reset, DRM_AUTH},
49         [DRM_IOCTL_NR(DRM_MACH64_VERTEX)] = {mach64_dma_vertex, DRM_AUTH},
50         [DRM_IOCTL_NR(DRM_MACH64_BLIT)] = {mach64_dma_blit, DRM_AUTH},
51         [DRM_IOCTL_NR(DRM_MACH64_FLUSH)] = {mach64_dma_flush, DRM_AUTH},
52         [DRM_IOCTL_NR(DRM_MACH64_GETPARAM)] = {mach64_get_param, DRM_AUTH},
53 };
54
55 int mach64_max_ioctl = DRM_ARRAY_SIZE(mach64_ioctls);
56
57 /* ================================================================
58  * DMA hardware state programming functions
59  */
60
61 static void mach64_print_dirty(const char *msg, unsigned int flags)
62 {
63         DRM_DEBUG("%s: (0x%x) %s%s%s%s%s%s%s%s%s%s%s%s\n",
64                   msg,
65                   flags,
66                   (flags & MACH64_UPLOAD_DST_OFF_PITCH) ? "dst_off_pitch, " :
67                   "",
68                   (flags & MACH64_UPLOAD_Z_ALPHA_CNTL) ? "z_alpha_cntl, " : "",
69                   (flags & MACH64_UPLOAD_SCALE_3D_CNTL) ? "scale_3d_cntl, " :
70                   "", (flags & MACH64_UPLOAD_DP_FOG_CLR) ? "dp_fog_clr, " : "",
71                   (flags & MACH64_UPLOAD_DP_WRITE_MASK) ? "dp_write_mask, " :
72                   "",
73                   (flags & MACH64_UPLOAD_DP_PIX_WIDTH) ? "dp_pix_width, " : "",
74                   (flags & MACH64_UPLOAD_SETUP_CNTL) ? "setup_cntl, " : "",
75                   (flags & MACH64_UPLOAD_MISC) ? "misc, " : "",
76                   (flags & MACH64_UPLOAD_TEXTURE) ? "texture, " : "",
77                   (flags & MACH64_UPLOAD_TEX0IMAGE) ? "tex0 image, " : "",
78                   (flags & MACH64_UPLOAD_TEX1IMAGE) ? "tex1 image, " : "",
79                   (flags & MACH64_UPLOAD_CLIPRECTS) ? "cliprects, " : "");
80 }
81
82 /* Mach64 doesn't have hardware cliprects, just one hardware scissor,
83  * so the GL scissor is intersected with each cliprect here
84  */
85 /* This function returns 0 on success, 1 for no intersection, and
86  * negative for an error
87  */
88 static int mach64_emit_cliprect(DRMFILE filp, drm_mach64_private_t * dev_priv,
89                                 drm_clip_rect_t * box)
90 {
91         u32 sc_left_right, sc_top_bottom;
92         drm_clip_rect_t scissor;
93         drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
94         drm_mach64_context_regs_t *regs = &sarea_priv->context_state;
95         DMALOCALS;
96
97         DRM_DEBUG("%s: box=%p\n", __FUNCTION__, box);
98
99         /* Get GL scissor */
100         /* FIXME: store scissor in SAREA as a cliprect instead of in
101          * hardware format, or do intersection client-side
102          */
103         scissor.x1 = regs->sc_left_right & 0xffff;
104         scissor.x2 = (regs->sc_left_right & 0xffff0000) >> 16;
105         scissor.y1 = regs->sc_top_bottom & 0xffff;
106         scissor.y2 = (regs->sc_top_bottom & 0xffff0000) >> 16;
107
108         /* Intersect GL scissor with cliprect */
109         if (box->x1 > scissor.x1)
110                 scissor.x1 = box->x1;
111         if (box->y1 > scissor.y1)
112                 scissor.y1 = box->y1;
113         if (box->x2 < scissor.x2)
114                 scissor.x2 = box->x2;
115         if (box->y2 < scissor.y2)
116                 scissor.y2 = box->y2;
117         /* positive return means skip */
118         if (scissor.x1 >= scissor.x2)
119                 return 1;
120         if (scissor.y1 >= scissor.y2)
121                 return 1;
122
123         DMAGETPTR(filp, dev_priv, 2);   /* returns on failure to get buffer */
124
125         sc_left_right = ((scissor.x1 << 0) | (scissor.x2 << 16));
126         sc_top_bottom = ((scissor.y1 << 0) | (scissor.y2 << 16));
127
128         DMAOUTREG(MACH64_SC_LEFT_RIGHT, sc_left_right);
129         DMAOUTREG(MACH64_SC_TOP_BOTTOM, sc_top_bottom);
130
131         DMAADVANCE(dev_priv, 1);
132
133         return 0;
134 }
135
136 static __inline__ int mach64_emit_state(DRMFILE filp,
137                                         drm_mach64_private_t * dev_priv)
138 {
139         drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
140         drm_mach64_context_regs_t *regs = &sarea_priv->context_state;
141         unsigned int dirty = sarea_priv->dirty;
142         u32 offset = ((regs->tex_size_pitch & 0xf0) >> 2);
143         DMALOCALS;
144
145         if (MACH64_VERBOSE) {
146                 mach64_print_dirty(__FUNCTION__, dirty);
147         } else {
148                 DRM_DEBUG("%s: dirty=0x%08x\n", __FUNCTION__, dirty);
149         }
150
151         DMAGETPTR(filp, dev_priv, 17);  /* returns on failure to get buffer */
152
153         if (dirty & MACH64_UPLOAD_MISC) {
154                 DMAOUTREG(MACH64_DP_MIX, regs->dp_mix);
155                 DMAOUTREG(MACH64_DP_SRC, regs->dp_src);
156                 DMAOUTREG(MACH64_CLR_CMP_CNTL, regs->clr_cmp_cntl);
157                 DMAOUTREG(MACH64_GUI_TRAJ_CNTL, regs->gui_traj_cntl);
158                 sarea_priv->dirty &= ~MACH64_UPLOAD_MISC;
159         }
160
161         if (dirty & MACH64_UPLOAD_DST_OFF_PITCH) {
162                 DMAOUTREG(MACH64_DST_OFF_PITCH, regs->dst_off_pitch);
163                 sarea_priv->dirty &= ~MACH64_UPLOAD_DST_OFF_PITCH;
164         }
165         if (dirty & MACH64_UPLOAD_Z_OFF_PITCH) {
166                 DMAOUTREG(MACH64_Z_OFF_PITCH, regs->z_off_pitch);
167                 sarea_priv->dirty &= ~MACH64_UPLOAD_Z_OFF_PITCH;
168         }
169         if (dirty & MACH64_UPLOAD_Z_ALPHA_CNTL) {
170                 DMAOUTREG(MACH64_Z_CNTL, regs->z_cntl);
171                 DMAOUTREG(MACH64_ALPHA_TST_CNTL, regs->alpha_tst_cntl);
172                 sarea_priv->dirty &= ~MACH64_UPLOAD_Z_ALPHA_CNTL;
173         }
174         if (dirty & MACH64_UPLOAD_SCALE_3D_CNTL) {
175                 DMAOUTREG(MACH64_SCALE_3D_CNTL, regs->scale_3d_cntl);
176                 sarea_priv->dirty &= ~MACH64_UPLOAD_SCALE_3D_CNTL;
177         }
178         if (dirty & MACH64_UPLOAD_DP_FOG_CLR) {
179                 DMAOUTREG(MACH64_DP_FOG_CLR, regs->dp_fog_clr);
180                 sarea_priv->dirty &= ~MACH64_UPLOAD_DP_FOG_CLR;
181         }
182         if (dirty & MACH64_UPLOAD_DP_WRITE_MASK) {
183                 DMAOUTREG(MACH64_DP_WRITE_MASK, regs->dp_write_mask);
184                 sarea_priv->dirty &= ~MACH64_UPLOAD_DP_WRITE_MASK;
185         }
186         if (dirty & MACH64_UPLOAD_DP_PIX_WIDTH) {
187                 DMAOUTREG(MACH64_DP_PIX_WIDTH, regs->dp_pix_width);
188                 sarea_priv->dirty &= ~MACH64_UPLOAD_DP_PIX_WIDTH;
189         }
190         if (dirty & MACH64_UPLOAD_SETUP_CNTL) {
191                 DMAOUTREG(MACH64_SETUP_CNTL, regs->setup_cntl);
192                 sarea_priv->dirty &= ~MACH64_UPLOAD_SETUP_CNTL;
193         }
194
195         if (dirty & MACH64_UPLOAD_TEXTURE) {
196                 DMAOUTREG(MACH64_TEX_SIZE_PITCH, regs->tex_size_pitch);
197                 DMAOUTREG(MACH64_TEX_CNTL, regs->tex_cntl);
198                 DMAOUTREG(MACH64_SECONDARY_TEX_OFF, regs->secondary_tex_off);
199                 DMAOUTREG(MACH64_TEX_0_OFF + offset, regs->tex_offset);
200                 sarea_priv->dirty &= ~MACH64_UPLOAD_TEXTURE;
201         }
202
203         DMAADVANCE(dev_priv, 1);
204
205         sarea_priv->dirty &= MACH64_UPLOAD_CLIPRECTS;
206
207         return 0;
208
209 }
210
211 /* ================================================================
212  * DMA command dispatch functions
213  */
214
215 static int mach64_dma_dispatch_clear(DRMFILE filp, drm_device_t * dev,
216                                      unsigned int flags,
217                                      int cx, int cy, int cw, int ch,
218                                      unsigned int clear_color,
219                                      unsigned int clear_depth)
220 {
221         drm_mach64_private_t *dev_priv = dev->dev_private;
222         drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
223         drm_mach64_context_regs_t *ctx = &sarea_priv->context_state;
224         int nbox = sarea_priv->nbox;
225         drm_clip_rect_t *pbox = sarea_priv->boxes;
226         u32 fb_bpp, depth_bpp;
227         int i;
228         DMALOCALS;
229
230         DRM_DEBUG("%s\n", __FUNCTION__);
231
232         switch (dev_priv->fb_bpp) {
233         case 16:
234                 fb_bpp = MACH64_DATATYPE_RGB565;
235                 break;
236         case 32:
237                 fb_bpp = MACH64_DATATYPE_ARGB8888;
238                 break;
239         default:
240                 return DRM_ERR(EINVAL);
241         }
242         switch (dev_priv->depth_bpp) {
243         case 16:
244                 depth_bpp = MACH64_DATATYPE_RGB565;
245                 break;
246         case 24:
247         case 32:
248                 depth_bpp = MACH64_DATATYPE_ARGB8888;
249                 break;
250         default:
251                 return DRM_ERR(EINVAL);
252         }
253
254         if (!nbox)
255                 return 0;
256
257         DMAGETPTR(filp, dev_priv, nbox * 31);   /* returns on failure to get buffer */
258
259         for (i = 0; i < nbox; i++) {
260                 int x = pbox[i].x1;
261                 int y = pbox[i].y1;
262                 int w = pbox[i].x2 - x;
263                 int h = pbox[i].y2 - y;
264
265                 DRM_DEBUG("dispatch clear %d,%d-%d,%d flags 0x%x\n",
266                           pbox[i].x1, pbox[i].y1,
267                           pbox[i].x2, pbox[i].y2, flags);
268
269                 if (flags & (MACH64_FRONT | MACH64_BACK)) {
270                         /* Setup for color buffer clears
271                          */
272
273                         DMAOUTREG(MACH64_Z_CNTL, 0);
274                         DMAOUTREG(MACH64_SCALE_3D_CNTL, 0);
275
276                         DMAOUTREG(MACH64_SC_LEFT_RIGHT, ctx->sc_left_right);
277                         DMAOUTREG(MACH64_SC_TOP_BOTTOM, ctx->sc_top_bottom);
278
279                         DMAOUTREG(MACH64_CLR_CMP_CNTL, 0);
280                         DMAOUTREG(MACH64_GUI_TRAJ_CNTL,
281                                   (MACH64_DST_X_LEFT_TO_RIGHT |
282                                    MACH64_DST_Y_TOP_TO_BOTTOM));
283
284                         DMAOUTREG(MACH64_DP_PIX_WIDTH, ((fb_bpp << 0) |
285                                                         (fb_bpp << 4) |
286                                                         (fb_bpp << 8) |
287                                                         (fb_bpp << 16) |
288                                                         (fb_bpp << 28)));
289
290                         DMAOUTREG(MACH64_DP_FRGD_CLR, clear_color);
291                         DMAOUTREG(MACH64_DP_WRITE_MASK, ctx->dp_write_mask);
292                         DMAOUTREG(MACH64_DP_MIX, (MACH64_BKGD_MIX_D |
293                                                   MACH64_FRGD_MIX_S));
294                         DMAOUTREG(MACH64_DP_SRC, (MACH64_BKGD_SRC_FRGD_CLR |
295                                                   MACH64_FRGD_SRC_FRGD_CLR |
296                                                   MACH64_MONO_SRC_ONE));
297
298                 }
299
300                 if (flags & MACH64_FRONT) {
301
302                         DMAOUTREG(MACH64_DST_OFF_PITCH,
303                                   dev_priv->front_offset_pitch);
304                         DMAOUTREG(MACH64_DST_X_Y, (y << 16) | x);
305                         DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (h << 16) | w);
306
307                 }
308
309                 if (flags & MACH64_BACK) {
310
311                         DMAOUTREG(MACH64_DST_OFF_PITCH,
312                                   dev_priv->back_offset_pitch);
313                         DMAOUTREG(MACH64_DST_X_Y, (y << 16) | x);
314                         DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (h << 16) | w);
315
316                 }
317
318                 if (flags & MACH64_DEPTH) {
319                         /* Setup for depth buffer clear
320                          */
321                         DMAOUTREG(MACH64_Z_CNTL, 0);
322                         DMAOUTREG(MACH64_SCALE_3D_CNTL, 0);
323
324                         DMAOUTREG(MACH64_SC_LEFT_RIGHT, ctx->sc_left_right);
325                         DMAOUTREG(MACH64_SC_TOP_BOTTOM, ctx->sc_top_bottom);
326
327                         DMAOUTREG(MACH64_CLR_CMP_CNTL, 0);
328                         DMAOUTREG(MACH64_GUI_TRAJ_CNTL,
329                                   (MACH64_DST_X_LEFT_TO_RIGHT |
330                                    MACH64_DST_Y_TOP_TO_BOTTOM));
331
332                         DMAOUTREG(MACH64_DP_PIX_WIDTH, ((depth_bpp << 0) |
333                                                         (depth_bpp << 4) |
334                                                         (depth_bpp << 8) |
335                                                         (depth_bpp << 16) |
336                                                         (depth_bpp << 28)));
337
338                         DMAOUTREG(MACH64_DP_FRGD_CLR, clear_depth);
339                         DMAOUTREG(MACH64_DP_WRITE_MASK, 0xffffffff);
340                         DMAOUTREG(MACH64_DP_MIX, (MACH64_BKGD_MIX_D |
341                                                   MACH64_FRGD_MIX_S));
342                         DMAOUTREG(MACH64_DP_SRC, (MACH64_BKGD_SRC_FRGD_CLR |
343                                                   MACH64_FRGD_SRC_FRGD_CLR |
344                                                   MACH64_MONO_SRC_ONE));
345
346                         DMAOUTREG(MACH64_DST_OFF_PITCH,
347                                   dev_priv->depth_offset_pitch);
348                         DMAOUTREG(MACH64_DST_X_Y, (y << 16) | x);
349                         DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (h << 16) | w);
350                 }
351         }
352
353         DMAADVANCE(dev_priv, 1);
354
355         return 0;
356 }
357
358 static int mach64_dma_dispatch_swap(DRMFILE filp, drm_device_t * dev)
359 {
360         drm_mach64_private_t *dev_priv = dev->dev_private;
361         drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
362         int nbox = sarea_priv->nbox;
363         drm_clip_rect_t *pbox = sarea_priv->boxes;
364         u32 fb_bpp;
365         int i;
366         DMALOCALS;
367
368         DRM_DEBUG("%s\n", __FUNCTION__);
369
370         switch (dev_priv->fb_bpp) {
371         case 16:
372                 fb_bpp = MACH64_DATATYPE_RGB565;
373                 break;
374         case 32:
375         default:
376                 fb_bpp = MACH64_DATATYPE_ARGB8888;
377                 break;
378         }
379
380         if (!nbox)
381                 return 0;
382
383         DMAGETPTR(filp, dev_priv, 13 + nbox * 4);       /* returns on failure to get buffer */
384
385         DMAOUTREG(MACH64_Z_CNTL, 0);
386         DMAOUTREG(MACH64_SCALE_3D_CNTL, 0);
387
388         DMAOUTREG(MACH64_SC_LEFT_RIGHT, 0 | (8191 << 16));      /* no scissor */
389         DMAOUTREG(MACH64_SC_TOP_BOTTOM, 0 | (16383 << 16));
390
391         DMAOUTREG(MACH64_CLR_CMP_CNTL, 0);
392         DMAOUTREG(MACH64_GUI_TRAJ_CNTL, (MACH64_DST_X_LEFT_TO_RIGHT |
393                                          MACH64_DST_Y_TOP_TO_BOTTOM));
394
395         DMAOUTREG(MACH64_DP_PIX_WIDTH, ((fb_bpp << 0) |
396                                         (fb_bpp << 4) |
397                                         (fb_bpp << 8) |
398                                         (fb_bpp << 16) | (fb_bpp << 28)));
399
400         DMAOUTREG(MACH64_DP_WRITE_MASK, 0xffffffff);
401         DMAOUTREG(MACH64_DP_MIX, (MACH64_BKGD_MIX_D | MACH64_FRGD_MIX_S));
402         DMAOUTREG(MACH64_DP_SRC, (MACH64_BKGD_SRC_BKGD_CLR |
403                                   MACH64_FRGD_SRC_BLIT | MACH64_MONO_SRC_ONE));
404
405         DMAOUTREG(MACH64_SRC_OFF_PITCH, dev_priv->back_offset_pitch);
406         DMAOUTREG(MACH64_DST_OFF_PITCH, dev_priv->front_offset_pitch);
407
408         for (i = 0; i < nbox; i++) {
409                 int x = pbox[i].x1;
410                 int y = pbox[i].y1;
411                 int w = pbox[i].x2 - x;
412                 int h = pbox[i].y2 - y;
413
414                 DRM_DEBUG("dispatch swap %d,%d-%d,%d\n",
415                           pbox[i].x1, pbox[i].y1, pbox[i].x2, pbox[i].y2);
416
417                 DMAOUTREG(MACH64_SRC_WIDTH1, w);
418                 DMAOUTREG(MACH64_SRC_Y_X, (x << 16) | y);
419                 DMAOUTREG(MACH64_DST_Y_X, (x << 16) | y);
420                 DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (h << 16) | w);
421
422         }
423
424         DMAADVANCE(dev_priv, 1);
425
426         if (dev_priv->driver_mode == MACH64_MODE_DMA_ASYNC) {
427                 for (i = 0; i < MACH64_MAX_QUEUED_FRAMES - 1; i++) {
428                         dev_priv->frame_ofs[i] = dev_priv->frame_ofs[i + 1];
429                 }
430                 dev_priv->frame_ofs[i] = GETRINGOFFSET();
431
432                 dev_priv->sarea_priv->frames_queued++;
433         }
434
435         return 0;
436 }
437
438 static int mach64_do_get_frames_queued(drm_mach64_private_t * dev_priv)
439 {
440         drm_mach64_descriptor_ring_t *ring = &dev_priv->ring;
441         drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
442         int i, start;
443         u32 head, tail, ofs;
444
445         DRM_DEBUG("%s\n", __FUNCTION__);
446
447         if (sarea_priv->frames_queued == 0)
448                 return 0;
449
450         tail = ring->tail;
451         mach64_ring_tick(dev_priv, ring);
452         head = ring->head;
453
454         start = (MACH64_MAX_QUEUED_FRAMES -
455                  DRM_MIN(MACH64_MAX_QUEUED_FRAMES, sarea_priv->frames_queued));
456
457         if (head == tail) {
458                 sarea_priv->frames_queued = 0;
459                 for (i = start; i < MACH64_MAX_QUEUED_FRAMES; i++) {
460                         dev_priv->frame_ofs[i] = ~0;
461                 }
462                 return 0;
463         }
464
465         for (i = start; i < MACH64_MAX_QUEUED_FRAMES; i++) {
466                 ofs = dev_priv->frame_ofs[i];
467                 DRM_DEBUG("frame_ofs[%d] ofs: %d\n", i, ofs);
468                 if (ofs == ~0 ||
469                     (head < tail && (ofs < head || ofs >= tail)) ||
470                     (head > tail && (ofs < head && ofs >= tail))) {
471                         sarea_priv->frames_queued =
472                             (MACH64_MAX_QUEUED_FRAMES - 1) - i;
473                         dev_priv->frame_ofs[i] = ~0;
474                 }
475         }
476
477         return sarea_priv->frames_queued;
478 }
479
480 /* Copy and verify a client submited buffer.
481  * FIXME: Make an assembly optimized version
482  */
483 static __inline__ int copy_from_user_vertex(u32 *to,
484                                             const u32 __user *ufrom,
485                                             unsigned long bytes)
486 {
487         unsigned long n = bytes;        /* dwords remaining in buffer */
488         u32 *from, *orig_from;
489
490         from = drm_alloc(bytes, DRM_MEM_DRIVER);
491         if (from == NULL)
492                 return DRM_ERR(ENOMEM);
493
494         if (DRM_COPY_FROM_USER(from, ufrom, bytes)) {
495                 drm_free(from, bytes, DRM_MEM_DRIVER);
496                 return DRM_ERR(EFAULT);
497         }
498         orig_from = from; /* we'll be modifying the "from" ptr, so save it */
499
500         n >>= 2;
501
502         while (n > 1) {
503                 u32 data, reg, count;
504
505                 data = *from++;
506
507                 n--;
508
509                 reg = le32_to_cpu(data);
510                 count = (reg >> 16) + 1;
511                 if (count <= n) {
512                         n -= count;
513                         reg &= 0xffff;
514
515                         /* This is an exact match of Mach64's Setup Engine registers,
516                          * excluding SETUP_CNTL (1_C1).
517                          */
518                         if ((reg >= 0x0190 && reg < 0x01c1) ||
519                             (reg >= 0x01ca && reg <= 0x01cf)) {
520                                 *to++ = data;
521                                 memcpy(to, from, count << 2);
522                                 from += count;
523                                 to += count;
524                         } else {
525                                 DRM_ERROR("%s: Got bad command: 0x%04x\n",
526                                           __FUNCTION__, reg);
527                                 drm_free(orig_from, bytes, DRM_MEM_DRIVER);
528                                 return DRM_ERR(EACCES);
529                         }
530                 } else {
531                         DRM_ERROR
532                             ("%s: Got bad command count(=%u) dwords remaining=%lu\n",
533                              __FUNCTION__, count, n);
534                         drm_free(orig_from, bytes, DRM_MEM_DRIVER);
535                         return DRM_ERR(EINVAL);
536                 }
537         }
538
539         drm_free(orig_from, bytes, DRM_MEM_DRIVER);
540         if (n == 0)
541                 return 0;
542         else {
543                 DRM_ERROR("%s: Bad buf->used(=%lu)\n", __FUNCTION__, bytes);
544                 return DRM_ERR(EINVAL);
545         }
546 }
547
548 static int mach64_dma_dispatch_vertex(DRMFILE filp, drm_device_t * dev,
549                                       drm_mach64_vertex_t * vertex)
550 {
551         drm_mach64_private_t *dev_priv = dev->dev_private;
552         drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
553         drm_buf_t *copy_buf;
554         void *buf = vertex->buf;
555         unsigned long used = vertex->used;
556         int ret = 0;
557         int i = 0;
558         int done = 0;
559         int verify_ret = 0;
560         DMALOCALS;
561
562         DRM_DEBUG("%s: buf=%p used=%lu nbox=%d\n",
563                   __FUNCTION__, buf, used, sarea_priv->nbox);
564
565         if (!used)
566                 goto _vertex_done;
567
568         copy_buf = mach64_freelist_get(dev_priv);
569         if (copy_buf == NULL) {
570                 DRM_ERROR("%s: couldn't get buffer\n", __FUNCTION__);
571                 return DRM_ERR(EAGAIN);
572         }
573
574         verify_ret = copy_from_user_vertex(GETBUFPTR(copy_buf), buf, used);
575
576         if (verify_ret != 0) {
577                 mach64_freelist_put(dev_priv, copy_buf);
578                 goto _vertex_done;
579         }
580
581         copy_buf->used = used;
582
583         DMASETPTR(copy_buf);
584
585         if (sarea_priv->dirty & ~MACH64_UPLOAD_CLIPRECTS) {
586                 ret = mach64_emit_state(filp, dev_priv);
587                 if (ret < 0)
588                         return ret;
589         }
590
591         do {
592                 /* Emit the next cliprect */
593                 if (i < sarea_priv->nbox) {
594                         ret = mach64_emit_cliprect(filp, dev_priv,
595                                                    &sarea_priv->boxes[i]);
596                         if (ret < 0) {
597                                 /* failed to get buffer */
598                                 return ret;
599                         } else if (ret != 0) {
600                                 /* null intersection with scissor */
601                                 continue;
602                         }
603                 }
604                 if ((i >= sarea_priv->nbox - 1))
605                         done = 1;
606
607                 /* Add the buffer to the DMA queue */
608                 DMAADVANCE(dev_priv, done);
609
610         } while (++i < sarea_priv->nbox);
611
612         if (!done) {
613                 if (copy_buf->pending) {
614                         DMADISCARDBUF();
615                 } else {
616                         /* This buffer wasn't used (no cliprects), so place it
617                          * back on the free list
618                          */
619                         mach64_freelist_put(dev_priv, copy_buf);
620                 }
621         }
622
623 _vertex_done:
624         sarea_priv->dirty &= ~MACH64_UPLOAD_CLIPRECTS;
625         sarea_priv->nbox = 0;
626
627         return verify_ret;
628 }
629
630 static __inline__ int copy_from_user_blit(u32 *to,
631                                           const u32 __user *ufrom,
632                                           unsigned long bytes)
633 {
634         to = (u32 *)((char *)to + MACH64_HOSTDATA_BLIT_OFFSET);
635
636         if (DRM_COPY_FROM_USER(to, ufrom, bytes)) {
637                 return DRM_ERR(EFAULT);
638         }
639
640         return 0;
641 }
642
643 static int mach64_dma_dispatch_blit(DRMFILE filp, drm_device_t * dev,
644                                     drm_mach64_blit_t * blit)
645 {
646         drm_mach64_private_t *dev_priv = dev->dev_private;
647         int dword_shift, dwords;
648         unsigned long used;
649         drm_buf_t *copy_buf;
650         int verify_ret = 0;
651         DMALOCALS;
652
653         /* The compiler won't optimize away a division by a variable,
654          * even if the only legal values are powers of two.  Thus, we'll
655          * use a shift instead.
656          */
657         switch (blit->format) {
658         case MACH64_DATATYPE_ARGB8888:
659                 dword_shift = 0;
660                 break;
661         case MACH64_DATATYPE_ARGB1555:
662         case MACH64_DATATYPE_RGB565:
663         case MACH64_DATATYPE_VYUY422:
664         case MACH64_DATATYPE_YVYU422:
665         case MACH64_DATATYPE_ARGB4444:
666                 dword_shift = 1;
667                 break;
668         case MACH64_DATATYPE_CI8:
669         case MACH64_DATATYPE_RGB8:
670                 dword_shift = 2;
671                 break;
672         default:
673                 DRM_ERROR("invalid blit format %d\n", blit->format);
674                 return DRM_ERR(EINVAL);
675         }
676
677         /* Set buf->used to the bytes of blit data based on the blit dimensions
678          * and verify the size.  When the setup is emitted to the buffer with
679          * the DMA* macros below, buf->used is incremented to include the bytes
680          * used for setup as well as the blit data.
681          */
682         dwords = (blit->width * blit->height) >> dword_shift;
683         used = dwords << 2;
684         if (used <= 0 ||
685             used > MACH64_BUFFER_SIZE - MACH64_HOSTDATA_BLIT_OFFSET) {
686                 DRM_ERROR("Invalid blit size: %lu bytes\n", used);
687                 return DRM_ERR(EINVAL);
688         }
689
690         copy_buf = mach64_freelist_get(dev_priv);
691         if (copy_buf == NULL) {
692                 DRM_ERROR("%s: couldn't get buffer\n", __FUNCTION__);
693                 return DRM_ERR(EAGAIN);
694         }
695
696         verify_ret = copy_from_user_blit(GETBUFPTR(copy_buf), blit->buf, used);
697
698         if (verify_ret != 0) {
699                 mach64_freelist_put(dev_priv, copy_buf);
700                 goto _blit_done;
701         }
702
703         copy_buf->used = used;
704
705         /* FIXME: Use a last buffer flag and reduce the state emitted for subsequent,
706          * continuation buffers?
707          */
708
709         /* Blit via BM_HOSTDATA (gui-master) - like HOST_DATA[0-15], but doesn't require
710          * a register command every 16 dwords.  State setup is added at the start of the
711          * buffer -- the client leaves space for this based on MACH64_HOSTDATA_BLIT_OFFSET
712          */
713         DMASETPTR(copy_buf);
714
715         DMAOUTREG(MACH64_Z_CNTL, 0);
716         DMAOUTREG(MACH64_SCALE_3D_CNTL, 0);
717
718         DMAOUTREG(MACH64_SC_LEFT_RIGHT, 0 | (8191 << 16));      /* no scissor */
719         DMAOUTREG(MACH64_SC_TOP_BOTTOM, 0 | (16383 << 16));
720
721         DMAOUTREG(MACH64_CLR_CMP_CNTL, 0);      /* disable */
722         DMAOUTREG(MACH64_GUI_TRAJ_CNTL,
723                   MACH64_DST_X_LEFT_TO_RIGHT | MACH64_DST_Y_TOP_TO_BOTTOM);
724
725         DMAOUTREG(MACH64_DP_PIX_WIDTH, (blit->format << 0)      /* dst pix width */
726                   |(blit->format << 4)  /* composite pix width */
727                   |(blit->format << 8)  /* src pix width */
728                   |(blit->format << 16) /* host data pix width */
729                   |(blit->format << 28) /* scaler/3D pix width */
730             );
731
732         DMAOUTREG(MACH64_DP_WRITE_MASK, 0xffffffff);    /* enable all planes */
733         DMAOUTREG(MACH64_DP_MIX, MACH64_BKGD_MIX_D | MACH64_FRGD_MIX_S);
734         DMAOUTREG(MACH64_DP_SRC,
735                   MACH64_BKGD_SRC_BKGD_CLR
736                   | MACH64_FRGD_SRC_HOST | MACH64_MONO_SRC_ONE);
737
738         DMAOUTREG(MACH64_DST_OFF_PITCH,
739                   (blit->pitch << 22) | (blit->offset >> 3));
740         DMAOUTREG(MACH64_DST_X_Y, (blit->y << 16) | blit->x);
741         DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (blit->height << 16) | blit->width);
742
743         DRM_DEBUG("%s: %lu bytes\n", __FUNCTION__, used);
744
745         /* Add the buffer to the queue */
746         DMAADVANCEHOSTDATA(dev_priv);
747
748 _blit_done:
749         return verify_ret;
750 }
751
752 /* ================================================================
753  * IOCTL functions
754  */
755
756 int mach64_dma_clear(DRM_IOCTL_ARGS)
757 {
758         DRM_DEVICE;
759         drm_mach64_private_t *dev_priv = dev->dev_private;
760         drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
761         drm_mach64_clear_t clear;
762         int ret;
763
764         DRM_DEBUG("%s: pid=%d\n", __FUNCTION__, DRM_CURRENTPID);
765
766         LOCK_TEST_WITH_RETURN(dev, filp);
767
768         DRM_COPY_FROM_USER_IOCTL(clear, (drm_mach64_clear_t *) data,
769                                  sizeof(clear));
770
771         if (sarea_priv->nbox > MACH64_NR_SAREA_CLIPRECTS)
772                 sarea_priv->nbox = MACH64_NR_SAREA_CLIPRECTS;
773
774         ret = mach64_dma_dispatch_clear(filp, dev, clear.flags,
775                                         clear.x, clear.y, clear.w, clear.h,
776                                         clear.clear_color, clear.clear_depth);
777
778         /* Make sure we restore the 3D state next time.
779          */
780         sarea_priv->dirty |= (MACH64_UPLOAD_CONTEXT | MACH64_UPLOAD_MISC);
781         return ret;
782 }
783
784 int mach64_dma_swap(DRM_IOCTL_ARGS)
785 {
786         DRM_DEVICE;
787         drm_mach64_private_t *dev_priv = dev->dev_private;
788         drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
789         int ret;
790
791         DRM_DEBUG("%s: pid=%d\n", __FUNCTION__, DRM_CURRENTPID);
792
793         LOCK_TEST_WITH_RETURN(dev, filp);
794
795         if (sarea_priv->nbox > MACH64_NR_SAREA_CLIPRECTS)
796                 sarea_priv->nbox = MACH64_NR_SAREA_CLIPRECTS;
797
798         ret = mach64_dma_dispatch_swap(filp, dev);
799
800         /* Make sure we restore the 3D state next time.
801          */
802         sarea_priv->dirty |= (MACH64_UPLOAD_CONTEXT | MACH64_UPLOAD_MISC);
803         return ret;
804 }
805
806 int mach64_dma_vertex(DRM_IOCTL_ARGS)
807 {
808         DRM_DEVICE;
809         drm_mach64_private_t *dev_priv = dev->dev_private;
810         drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
811         drm_mach64_vertex_t vertex;
812
813         LOCK_TEST_WITH_RETURN(dev, filp);
814
815         if (!dev_priv) {
816                 DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
817                 return DRM_ERR(EINVAL);
818         }
819
820         DRM_COPY_FROM_USER_IOCTL(vertex, (drm_mach64_vertex_t *) data,
821                                  sizeof(vertex));
822
823         DRM_DEBUG("%s: pid=%d buf=%p used=%lu discard=%d\n",
824                   __FUNCTION__, DRM_CURRENTPID,
825                   vertex.buf, vertex.used, vertex.discard);
826
827         if (vertex.prim < 0 || vertex.prim > MACH64_PRIM_POLYGON) {
828                 DRM_ERROR("buffer prim %d\n", vertex.prim);
829                 return DRM_ERR(EINVAL);
830         }
831
832         if (vertex.used > MACH64_BUFFER_SIZE || (vertex.used & 3) != 0) {
833                 DRM_ERROR("Invalid vertex buffer size: %lu bytes\n",
834                           vertex.used);
835                 return DRM_ERR(EINVAL);
836         }
837
838         if (sarea_priv->nbox > MACH64_NR_SAREA_CLIPRECTS)
839                 sarea_priv->nbox = MACH64_NR_SAREA_CLIPRECTS;
840
841         return mach64_dma_dispatch_vertex(filp, dev, &vertex);
842 }
843
844 int mach64_dma_blit(DRM_IOCTL_ARGS)
845 {
846         DRM_DEVICE;
847         drm_mach64_private_t *dev_priv = dev->dev_private;
848         drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
849         drm_mach64_blit_t blit;
850         int ret;
851
852         LOCK_TEST_WITH_RETURN(dev, filp);
853
854         DRM_COPY_FROM_USER_IOCTL(blit, (drm_mach64_blit_t *) data,
855                                  sizeof(blit));
856
857         ret = mach64_dma_dispatch_blit(filp, dev, &blit);
858
859         /* Make sure we restore the 3D state next time.
860          */
861         sarea_priv->dirty |= (MACH64_UPLOAD_CONTEXT |
862                               MACH64_UPLOAD_MISC | MACH64_UPLOAD_CLIPRECTS);
863
864         return ret;
865 }
866
867 int mach64_get_param(DRM_IOCTL_ARGS)
868 {
869         DRM_DEVICE;
870         drm_mach64_private_t *dev_priv = dev->dev_private;
871         drm_mach64_getparam_t param;
872         int value;
873
874         DRM_DEBUG("%s\n", __FUNCTION__);
875
876         if (!dev_priv) {
877                 DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
878                 return DRM_ERR(EINVAL);
879         }
880
881         DRM_COPY_FROM_USER_IOCTL(param, (drm_mach64_getparam_t *) data,
882                                  sizeof(param));
883
884         switch (param.param) {
885         case MACH64_PARAM_FRAMES_QUEUED:
886                 /* Needs lock since it calls mach64_ring_tick() */
887                 LOCK_TEST_WITH_RETURN(dev, filp);
888                 value = mach64_do_get_frames_queued(dev_priv);
889                 break;
890         case MACH64_PARAM_IRQ_NR:
891                 value = dev->irq;
892                 break;
893         default:
894                 return DRM_ERR(EINVAL);
895         }
896
897         if (DRM_COPY_TO_USER(param.value, &value, sizeof(int))) {
898                 DRM_ERROR("copy_to_user\n");
899                 return DRM_ERR(EFAULT);
900         }
901
902         return 0;
903 }