xref: /haiku/src/add-ons/accelerants/et6x00/Acceleration.c (revision 3cb015b1ee509d69c643506e8ff573808c86dcfc)
1 /*****************************************************************************\
2  * Tseng Labs ET6000, ET6100 and ET6300 graphics driver for BeOS 5.
3  * Copyright (c) 2003-2004, Evgeniy Vladimirovich Bobkov.
4 \*****************************************************************************/
5 
6 #include "GlobalData.h"
7 #include "generic.h"
8 
9 
10 /*****************************************************************************/
11 /*
12  * Set bits in a byte pointed by addr; mask must contain 0s at the bits
13  * positions to be set and must contain 1s at all other bits; val must
14  * contain the values of bits to be set.
15  */
16 __inline void set8(volatile char *addr, char mask, char val)
17 {
18     if (mask == 0)
19         *addr = val;
20     else
21         *addr = (*addr & mask) | (val & ~mask);
22 }
23 /*****************************************************************************/
24 __inline char get8(volatile char *addr)
25 {
26     return *addr;
27 }
28 /*****************************************************************************/
29 __inline void et6000aclTerminate(void) {
30     set8(mmRegs+0x31, 0xef, 0x10); /* let ACL to operate */
31     et6000aclWaitIdle();
32     set8(mmRegs+0x30, 0, 0x00);
33     set8(mmRegs+0x30, 0, 0x01);
34     et6000aclWaitIdle();
35     set8(mmRegs+0x30, 0, 0x00);
36     set8(mmRegs+0x30, 0, 0x10);
37     et6000aclWaitIdle();
38     set8(mmRegs+0x30, 0, 0x00);
39 }
40 /*****************************************************************************/
41 /*
42  * bpp must be bytes per pixel, not bits!
43  */
44 void et6000aclInit(uint8 bpp) {
45 
46     et6000aclTerminate();
47 
48     set8(mmRegs+0x31, 0xef, 0x10); /* let ACL to operate */
49     set8(mmRegs+0x32, 0x99, 0x00); /* maximize the performance */
50     set8(mmRegs+0x8e, 0xcf, (bpp - 1) << 4); /* set pixel color depth */
51     set8(mmRegs+0x91, 0x80, 0x00); /* maximize the performance */
52     set8(mmRegs+0x9d, 0x00, 0x00); /* maximize the performance */
53 }
54 /*****************************************************************************/
55 /*
56  * Wait until ACL becomes idle.
57  */
58 void et6000aclWaitIdle(void) {
59     while ((get8(mmRegs+0x36) & 0x02) == 0x02);
60 }
61 /*****************************************************************************/
62 /*
63  * Wait until ACL queue becomes not full.
64  */
65 __inline void et6000aclWaitQueueNotFull(void) {
66     while ((get8(mmRegs+0x36) & 0x01) == 0x01);
67 }
68 /*****************************************************************************/
69 /*
70  * Move the specified list of rectangular regions from one location in
71  * the frame buffer to another in the order they are specified in the
72  * blit_params *list. The list is uint32 count elements in length.
73  */
74 void SCREEN_TO_SCREEN_BLIT(engine_token *et,
75                            blit_params *list,
76                            uint32 count)
77 {
78 uint16 screenWidth = si->dm.virtual_width;
79 uint8 bpp = si->bytesPerPixel;
80 uint8 bltDir;
81 uint16 src_left, src_top, dest_left, dest_top, width, height;
82 uint32 srcAddr, destAddr;
83 
84     et6000aclWaitQueueNotFull();
85 
86     set8(mmRegs+0x92, 0x80, 0x77); /* no source wrap */
87     set8(mmRegs+0x9c, 0x00, 0x33); /* mask=1 always, always use FGR */
88     set8(mmRegs+0x9f, 0x00, 0xcc); /* FGR ROP = copy of source */
89 
90     /* Set the source Y offset */
91     *((vuint16 *)(mmRegs+0x8a)) = screenWidth * bpp - 1;
92 
93     /* Set the destination Y offset */
94     *((vuint16 *)(mmRegs+0x8c)) = screenWidth * bpp - 1;
95 
96     while(count--) {
97         src_left = list->src_left;
98         src_top = list->src_top;
99         dest_left = list->dest_left;
100         dest_top = list->dest_top;
101         width = list->width;
102         height = list->height;
103 
104         et6000aclWaitQueueNotFull();
105 
106         /* Set the direction and opcode(BitBLT) register */
107         bltDir = 0x00;
108         if (src_left < dest_left) bltDir |= 0x01;
109         if (src_top < dest_top) bltDir |= 0x02;
110         set8(mmRegs+0x8f, 0x3c, bltDir);
111 
112         /* Set the X count register */
113         *((vuint16 *)(mmRegs+0x98)) = (width + 1) * bpp - 1;
114 
115         /* Set the Y count register */
116         *((vuint16 *)(mmRegs+0x9a)) = height;
117 
118         switch (bltDir & 0x03) {
119         case 0x00:
120             srcAddr = (src_top * screenWidth + src_left) * bpp;
121             destAddr = (dest_top * screenWidth + dest_left) * bpp;
122             break;
123 
124         case 0x01:
125             srcAddr =  (src_top * screenWidth + src_left + width) * bpp + bpp-1;
126             destAddr = (dest_top * screenWidth + dest_left + width) * bpp + bpp-1;
127             break;
128 
129         case 0x02:
130             srcAddr = ((src_top + height)*screenWidth + src_left) * bpp;
131             destAddr = ((dest_top + height)*screenWidth + dest_left) * bpp;
132             break;
133 
134         case 0x03:
135             srcAddr = ((src_top + height)*screenWidth + src_left + width) * bpp + bpp-1;
136             destAddr = ((dest_top + height)*screenWidth + dest_left + width) * bpp + bpp-1;
137             break;
138         }
139 
140         /* Set the source address */
141         *((vuint32 *)(mmRegs+0x84)) = srcAddr;
142 
143         /*
144          * Set the destination address -
145          * this action starts the BitBLT operation.
146          */
147         *((vuint32 *)(mmRegs+0xa0)) = destAddr;
148 
149         list++;
150     }
151 
152     si->engine.count++;
153 }
154 /*****************************************************************************/
155 /*
156  * Fill the specified list of rectangular regions with the specified color.
157  * The list is uint32 count elements in length. The rectangular regions are
158  * inclusive. The uint32 color is specified in the same configuration and
159  * byte order as the current display_mode. All coordinates in the list of
160  * rectangles is guaranteed to have been clipped to the virtual limits of
161  * the display_mode.
162  */
163 void FILL_RECTANGLE(engine_token *et,
164                     uint32 color,
165                     fill_rect_params *list,
166                     uint32 count)
167 {
168 uint16 screenWidth = si->dm.virtual_width;
169 uint8 bpp = si->bytesPerPixel;
170 uint16 left, top, right, bottom;
171 uint32 srcAddr;
172 uint8 i;
173 
174     /*
175      * Normally WaitQueueNotFull should be required & enough, but in reality
176      * this is somewhy sometimes not enough for pixel depth of 3 bytes.
177      */
178     if (bpp == 2)
179         et6000aclWaitQueueNotFull();
180     else
181         et6000aclWaitIdle();
182 
183     /*
184      * We'll put the color at 4 bytes just after the framebuffer.
185      * The srcAddr must be 4 bytes aligned and is always for standard
186      * resolutions.
187      */
188     srcAddr = (uint32)si->framebuffer - (uint32)si->memory +
189         si->dm.virtual_width * si->dm.virtual_height * bpp;
190 
191     switch(bpp) {
192         case 2:
193             set8(mmRegs+0x92, 0x80, 0x02); /* 4x1 source wrap */
194             for (i = 0; i < 2; i++) /* copy the color to source address */
195                 ((vuint16 *)((uint32)si->memory + srcAddr))[i] = (uint16)color;
196             break;
197         case 3:
198             set8(mmRegs+0x92, 0x80, 0x0a); /* 3x1 source wrap */
199             for (i = 0; i < 3; i++) /* copy the color to source address */
200                 ((vuint8 *)((uint32)si->memory + srcAddr))[i] = ((uint8 *)&color)[i];
201 
202             break;
203     }
204 
205     set8(mmRegs+0x9c, 0x00, 0x33); /* mask=1 always, always use FGR */
206     set8(mmRegs+0x9f, 0x00, 0xcc); /* FGR ROP = copy of source */
207 
208     /* Set the source Y offset */
209     *((vuint16 *)(mmRegs+0x8a)) = screenWidth * bpp - 1;
210     /* Set the destination Y offset */
211     *((vuint16 *)(mmRegs+0x8c)) = screenWidth * bpp - 1;
212 
213     /* Set the direction and opcode(trapezoid) register (primary edge) */
214     set8(mmRegs+0x8f, 0x18, 0x40);
215     /* Set the secondary edge register */
216     set8(mmRegs+0x93, 0x1a, 0x00);
217 
218     /* Set the primary delta minor register */
219     *((vuint16 *)(mmRegs+0xac)) = 0;
220     /* Set the secondary delta minor register */
221     *((vuint16 *)(mmRegs+0xb4)) = 0;
222 
223     while(count--) {
224         left = list->left;
225         top = list->top;
226         right = list->right;
227         bottom = list->bottom;
228 
229         et6000aclWaitQueueNotFull();
230 
231         /* Set the X count register */
232         *((vuint16 *)(mmRegs+0x98)) = (right-left+1)*bpp - 1;
233         /* Set the Y count register */
234         *((vuint16 *)(mmRegs+0x9a)) = bottom-top;
235 
236         /* Set the primary delta major register */
237         *((vuint16 *)(mmRegs+0xae)) = bottom-top;
238 
239         /* Set the secondary delta major register */
240         *((vuint16 *)(mmRegs+0xb6)) = bottom-top;
241 
242         /* Set the source address */
243         *((vuint32 *)(mmRegs+0x84)) = srcAddr;
244 
245         /*
246          * Set the destination address -
247          * this action starts the trapezoid operation.
248          */
249         *((vuint32 *)(mmRegs+0xa0)) = (top * screenWidth + left) * bpp;
250 
251         list++;
252     }
253 
254     si->engine.count++;
255 }
256 /*****************************************************************************/
257