1 /*
2    Copyright (c) 2003 Andreas Robinson, All rights reserved.
3 
4    This library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2 of the License, or (at your option) any later version.
8 */
9 
10 #ifndef __UC_FIFO_H__
11 #define __UC_FIFO_H__
12 
13 // Note to self: remove when added to makefile as -DUC_DEBUG.
14 #define UC_DEBUG 1
15 
16 #include <dfb_types.h>
17 
18 #include "regs2d.h"
19 #include "regs3d.h"
20 #include "mmio.h"
21 
22 /**
23  * uc_fifo - GPU data queue.
24  *
25  * buf:         buffer start (userspace address)
26  * head:        pointer to first unused entry.
27  *
28  * size:        maximum number of entries in the fifo.
29  * prep:        number of entries allocated to be used.
30  * used:        number of entries currently in use.
31  *
32  * hwregs:      GPU register base address
33  * reg_tset:    address to GPU TRANSET register
34  * reg_tspace:  address to GPU TRANSPACE register
35  *
36  * flush:       function pointer to flush function (DMA or CPU)
37  * flush_sys:   function pointer to flush_sys (non-DMA) function
38  */
39 
40 struct uc_fifo
41 {
42     u32* buf;
43     u32* head;
44 
45     unsigned int size;
46     unsigned int prep;
47     unsigned int used;
48 
49     //void (*flush)(struct uc_fifo* fifo, volatile void *hwregs);
50     //void (*flush_sys)(struct uc_fifo* fifo, volatile void *hwregs);
51 };
52 
53 // Help macros ---------------------------------------------------------------
54 
55 // For the record: Macros suck maintenance- and debugging-wise,
56 // but provide guaranteed inlining of the code.
57 
58 /**
59  * Send the contents of the FIFO buffer to the hardware, and clear
60  * the buffer. The transfer may be performed by the CPU or by DMA.
61  */
62 
63 //#define UC_FIFO_FLUSH(fifo) (fifo)->flush(fifo,ucdrv->hwregs)
64 
65 /**
66  * Same as UC_FIFO_FLUSH(), but always uses the CPU to transfer data.
67  */
68 
69 //#define UC_FIFO_FLUSH_SYS(fifo) (fifo)->flush_sys(fifo,ucdrv->hwregs)
70 
71 #define UC_FIFO_FLUSH(fifo)     uc_fifo_flush_sys(fifo,ucdrv->hwregs)
72 #define UC_FIFO_FLUSH_SYS(fifo) uc_fifo_flush_sys(fifo,ucdrv->hwregs)
73 
74 /**
75  * Make sure there is room for dwsize double words in the FIFO.
76  * If necessary, the FIFO is flushed first.
77  *
78  * @param fifo      the fifo
79  * @param dwsize    number of double words to allocate
80  *
81  * @note It is ok to request more space than you will actually
82  * be using. This is useful when you don't know exactly beforehand
83  * how many entries you need.
84  *
85  * @note equivalent DRI code is in via_ioctl.c::viaCheckDma()
86  */
87 
88 #ifdef UC_DEBUG
89 
90 #define UC_FIFO_PREPARE(fifo, dwsize)                       \
91     do {                                                    \
92         if ((fifo)->used + dwsize + 32 > (fifo)->size) {    \
93             D_DEBUG("CLE266: FIFO full - flushing it.");   \
94             UC_FIFO_FLUSH(fifo);                            \
95         }                                                   \
96         if (dwsize + (fifo)->prep + 32 > (fifo)->size) {    \
97             D_BUG("CLE266: FIFO too small for allocation.");  \
98         }                                                   \
99         (fifo)->prep += dwsize;                             \
100     } while(0)
101 
102 #else
103 
104 #define UC_FIFO_PREPARE(fifo, dwsize)                       \
105     do {                                                    \
106         if ((fifo)->used + dwsize + 32 > (fifo)->size) {    \
107             UC_FIFO_FLUSH(fifo);                            \
108         }                                                   \
109         (fifo)->prep += dwsize;                             \
110     } while(0)
111 
112 #endif // UC_FIFO_DEBUG
113 
114 /**
115  * Add a 32-bit data word to the FIFO.
116  * Takes one entry in the FIFO.
117  */
118 
119 #define UC_FIFO_ADD(fifo, data)     \
120     do {                            \
121         *((fifo)->head) = (data);   \
122         (fifo)->head++;             \
123         (fifo)->used++;             \
124     } while(0)
125 
126 /**
127  * Add a command header. (HC_HEADER2 + parameter selection)
128  * Takes two entries in the fifo.
129  */
130 
131 #define UC_FIFO_ADD_HDR(fifo, param)    \
132     do {                                \
133         UC_FIFO_ADD(fifo, HC_HEADER2);  \
134         UC_FIFO_ADD(fifo, param);       \
135     } while(0);
136 
137 /**
138  * Add a floating point value to the FIFO.
139  * Non-floats (e.g integers) are converted first.
140  * Takes one entry in the FIFO.
141  */
142 
143 #define UC_FIFO_ADD_FLOAT(fifo, val)        \
144     do {                                    \
145         union {float f; u32 i;} v;          \
146         v.f = (float) (val);                \
147         UC_FIFO_ADD(fifo, v.i);             \
148     } while(0)
149 
150 /**
151  * Add a vertex on the form (x, y, color) to the FIFO.
152  * Takes three entries in the FIFO.
153  * The color format is 0xAARRGGBB.
154  */
155 
156 #define UC_FIFO_ADD_XYC(fifo, x, y, color)  \
157     do {                                    \
158         UC_FIFO_ADD_FLOAT(fifo, x);         \
159         UC_FIFO_ADD_FLOAT(fifo, y);         \
160         UC_FIFO_ADD(fifo, color);           \
161     } while(0)
162 
163 /**
164  * Add a vertex on the form (x, y, w, color, s, t) to the FIFO.
165  * Takes six entries in the FIFO.
166  * The color format is 0xAARRGGBB.
167  */
168 
169 #define UC_FIFO_ADD_XYWCST(fifo, x, y, w, color, s, t)  \
170     do {                                                \
171         UC_FIFO_ADD_FLOAT(fifo, x);                     \
172         UC_FIFO_ADD_FLOAT(fifo, y);                     \
173         UC_FIFO_ADD_FLOAT(fifo, w);                     \
174         UC_FIFO_ADD(fifo, color);                       \
175         UC_FIFO_ADD_FLOAT(fifo, s);                     \
176         UC_FIFO_ADD_FLOAT(fifo, t);                     \
177     } while(0)
178 
179 #define UC_FIFO_ADD_XYZWCST(fifo, x, y, z, w, color, s, t)  \
180     do {                                                \
181         UC_FIFO_ADD_FLOAT(fifo, x);                     \
182         UC_FIFO_ADD_FLOAT(fifo, y);                     \
183         UC_FIFO_ADD_FLOAT(fifo, z);                     \
184         UC_FIFO_ADD_FLOAT(fifo, w);                     \
185         UC_FIFO_ADD(fifo, color);                       \
186         UC_FIFO_ADD_FLOAT(fifo, s);                     \
187         UC_FIFO_ADD_FLOAT(fifo, t);                     \
188     } while(0)
189 
190 #define UC_FIFO_ADD_XYCST(fifo, x, y, color, s, t)      \
191     do {                                                \
192         UC_FIFO_ADD_FLOAT(fifo, x);                     \
193         UC_FIFO_ADD_FLOAT(fifo, y);                     \
194         UC_FIFO_ADD(fifo, color);                       \
195         UC_FIFO_ADD_FLOAT(fifo, s);                     \
196         UC_FIFO_ADD_FLOAT(fifo, t);                     \
197     } while(0)
198 
199 
200 /**
201  * Add data specifically for the 2D controller, to the fifo.
202  * Takes two entries in the FIFO.
203  *
204  * @param reg   2D register index
205  * @param data  32-bit data to add
206  */
207 
208 #define UC_FIFO_ADD_2D(fifo, reg, data)                     \
209     do {                                                    \
210         UC_FIFO_ADD(fifo, ((reg) >> 2) | HALCYON_HEADER1);  \
211         UC_FIFO_ADD(fifo, (data));                          \
212     } while (0)
213 
214 /**
215  * Add data specifically for a 3D controller register, to the fifo.
216  * Takes one entry in the FIFO.
217  *
218  * @param reg   3D register index (8 bit)
219  * @param data  24-bit data to add (make sure bits 24 - 31 are cleared!)
220  */
221 
222 #define UC_FIFO_ADD_3D(fifo, reg, data) \
223     UC_FIFO_ADD(fifo, ((reg) << 24) | (data))
224 
225 /**
226  * Pad the FIFO to an even number of entries.
227  * Takes zero or one entries in the FIFO.
228  */
229 #define UC_FIFO_PAD_EVEN(fifo)  \
230         if (fifo->used & 1) UC_FIFO_ADD(fifo, HC_DUMMY)
231 
232 /**
233  * Check for buffer overruns.
234  * Can be redefined to nothing in release builds.
235  */
236 
237 #ifdef UC_DEBUG
238 
239 #define UC_FIFO_CHECK(fifo)                         \
240     do {                                            \
241         if ((fifo)->used > ((fifo)->size) - 32) {   \
242             D_BUG("CLE266: FIFO overrun.");           \
243         }                                           \
244         if ((fifo)->used > (fifo)->prep) {          \
245             D_BUG("CLE266: FIFO allocation error.");  \
246         }                                           \
247     } while(0)
248 
249 #else
250 
251 #define UC_FIFO_CHECK(fifo) do { } while(0)
252 
253 #endif // UC_DEBUG
254 
255 
256 // FIFO functions ------------------------------------------------------------
257 
258 /** Create a FIFO. Returns NULL on failure. */
259 
260 struct uc_fifo* uc_fifo_create(FusionSHMPoolShared *pool, size_t size);
261 
262 /** Destroy a FIFO */
263 
264 void uc_fifo_destroy(FusionSHMPoolShared *pool, struct uc_fifo* fifo);
265 
266 void uc_fifo_flush_sys(struct uc_fifo* fifo, volatile void *regs);
267 
268 #endif // __UC_FIFO_H__
269