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 */
16static __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/*****************************************************************************/
25static __inline unsigned char get8(volatile unsigned char *addr)
26{
27    return *addr;
28}
29/*****************************************************************************/
30static __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 */
45void 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 */
59void et6000aclWaitIdle(void) {
60    while ((get8(mmRegs+0x36) & 0x02) == 0x02);
61}
62/*****************************************************************************/
63/*
64 * Wait until ACL queue becomes not full.
65 */
66static __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 */
75void SCREEN_TO_SCREEN_BLIT(engine_token *et,
76                           blit_params *list,
77                           uint32 count)
78{
79uint16 screenWidth = si->dm.virtual_width;
80uint8 bpp = si->bytesPerPixel;
81uint8 bltDir;
82uint16 src_left, src_top, dest_left, dest_top, width, height;
83uint32 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 */
164void FILL_RECTANGLE(engine_token *et,
165                    uint32 color,
166                    fill_rect_params *list,
167                    uint32 count)
168{
169uint16 screenWidth = si->dm.virtual_width;
170uint8 bpp = si->bytesPerPixel;
171uint16 left, top, right, bottom;
172uint32 srcAddr;
173uint8 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