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