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 #include <config.h>
11 
12 #include <stdio.h>
13 #include <stdlib.h>
14 
15 #include <fusion/shmalloc.h>
16 
17 #include "uc_fifo.h"
18 
19 //#define UC_FIFO_DUMP_DATA
20 
21 // Private functions ---------------------------------------------------------
22 
23 /**
24  * Pad the FIFO buffer to a 32 byte boundary. Used by uc_flush_agp().
25  * @note Equivalent DRI code is in via_ioctl::viaFlushPrimsLocked()
26  */
27 
uc_fifo_pad(struct uc_fifo * fifo)28 static void uc_fifo_pad(struct uc_fifo* fifo)
29 {
30     switch (fifo->used & 0x7)
31     {
32     case 0:
33         break;
34     case 2:
35         UC_FIFO_ADD(fifo, HALCYON_HEADER2);
36         UC_FIFO_ADD(fifo, HC_ParaType_NotTex << 16);
37         UC_FIFO_ADD(fifo, HC_DUMMY);
38         UC_FIFO_ADD(fifo, HC_DUMMY);
39         UC_FIFO_ADD(fifo, HC_DUMMY);
40         UC_FIFO_ADD(fifo, HC_DUMMY);
41         break;
42     case 4:
43         UC_FIFO_ADD(fifo, HALCYON_HEADER2);
44         UC_FIFO_ADD(fifo, HC_ParaType_NotTex << 16);
45         UC_FIFO_ADD(fifo, HC_DUMMY);
46         UC_FIFO_ADD(fifo, HC_DUMMY);
47         break;
48     case 6:
49         UC_FIFO_ADD(fifo, HALCYON_HEADER2);
50         UC_FIFO_ADD(fifo, HC_ParaType_NotTex << 16);
51         UC_FIFO_ADD(fifo, HC_DUMMY);
52         UC_FIFO_ADD(fifo, HC_DUMMY);
53         UC_FIFO_ADD(fifo, HC_DUMMY);
54         UC_FIFO_ADD(fifo, HC_DUMMY);
55         UC_FIFO_ADD(fifo, HC_DUMMY);
56         UC_FIFO_ADD(fifo, HC_DUMMY);
57         UC_FIFO_ADD(fifo, HC_DUMMY);
58         UC_FIFO_ADD(fifo, HC_DUMMY);
59         break;
60     default:
61         break;
62     }
63 }
64 
65 /**
66  * Manually write the FIFO buffer to the hardware.
67  * @note Equivalent DRI code is in via_ioctl::flush_sys()
68  */
69 
uc_fifo_flush_sys(struct uc_fifo * fifo,volatile void * regs)70 void uc_fifo_flush_sys(struct uc_fifo* fifo, volatile void *regs)
71 {
72     u32* p;
73     u32* q;
74 
75     volatile u32* hwregs     = regs;
76     volatile u32* reg_tset   = regs + VIA_REG_TRANSET;
77     volatile u32* reg_tspace = regs + VIA_REG_TRANSPACE;
78 
79     int check2Dcmd;
80     u32 addr;
81 
82     p = fifo->buf;
83     q = fifo->head;
84     check2Dcmd = 0;
85 
86     uc_fifo_pad(fifo);
87 
88 #ifdef UC_FIFO_DUMP_DATA
89     printf("Flushing FIFO ... \n");
90 #endif
91 
92     while (p != q) {
93 
94         if (*p == HALCYON_HEADER2) {
95             p++;
96             check2Dcmd = !(*p == HALCYON_SUB_ADDR0);
97 #ifdef UC_FIFO_DUMP_DATA
98             printf("tset = 0x%08x\n", *p);
99 #endif
100             *reg_tset = *p;
101             p++;
102         }
103         else if (check2Dcmd && ((*p & HALCYON_HEADER1MASK) == HALCYON_HEADER1)) {
104             addr = (*p) & 0x0000001f;
105             p++;
106 #ifdef UC_FIFO_DUMP_DATA
107             printf("2D (0x%02x) = 0x%x\n", addr << 2, *p);
108 #endif
109             *(hwregs + addr) = *p;
110             p++;
111         }
112         else if ((*p & HALCYON_FIREMASK) == HALCYON_FIRECMD) {
113 #ifdef UC_FIFO_DUMP_DATA
114             printf("tspace = 0x%08x\n", *p);
115 #endif
116             *reg_tspace = *p;
117             p++;
118 
119             if ((p != q) && ((*p & HALCYON_FIREMASK) == HALCYON_FIRECMD))
120                 p++;
121 
122             if ((*p & HALCYON_CMDBMASK) != HC_ACMD_HCmdB)
123                 check2Dcmd = 1;
124         }
125         else {
126 #ifdef UC_FIFO_DUMP_DATA
127             printf("tspace = 0x%08x\n", *p);
128 #endif
129             *reg_tspace = *p;
130             p++;
131         }
132     }
133 
134     fifo->head = fifo->buf;
135     fifo->used = 0;
136     fifo->prep = 0;
137 }
138 
139 /** Use an AGP transfer to write the FIFO buffer to the hardware. Not implemented. */
140 #if 0
141 static void uc_fifo_flush_agp(struct uc_fifo* fifo)
142 {
143     // TODO - however, there is no point in doing this, because
144     // an AGP transfer can require more register writes than
145     // needed for drawing a single primitive. DirectFB needs to
146     // adopt a begin/end architecture first, like OpenGL has.
147 
148     fifo->head = fifo->buf;
149     fifo->used = 0;
150     fifo->prep = 0;
151 }
152 #endif
153 
154 // Public functions ----------------------------------------------------------
155 
156 /** Create a FIFO. Returns NULL on failure. */
157 
uc_fifo_create(FusionSHMPoolShared * pool,size_t size)158 struct uc_fifo* uc_fifo_create(FusionSHMPoolShared *pool, size_t size)
159 {
160     struct uc_fifo* fifo;
161 
162     size += 32;     // Needed for padding.
163 
164     fifo = SHCALLOC(pool, 1, sizeof(struct uc_fifo));
165     if (!fifo) return NULL;
166 
167     // Note: malloc won't work for DMA buffers...
168 
169     fifo->buf = SHMALLOC(pool, sizeof(u32) * size);
170     if (!(fifo->buf)) {
171         SHFREE(pool, fifo);
172         return NULL;
173     }
174 
175     fifo->head = fifo->buf;
176     fifo->used = 0;
177     fifo->size = (unsigned int) size;
178     fifo->prep = 0;
179 
180     //fifo->flush_sys = uc_fifo_flush_sys;
181 
182     //fifo->flush = uc_fifo_flush_sys;
183 
184     return fifo;
185 }
186 
187 /** Destroy a FIFO */
188 
uc_fifo_destroy(FusionSHMPoolShared * pool,struct uc_fifo * fifo)189 void uc_fifo_destroy(FusionSHMPoolShared *pool, struct uc_fifo* fifo)
190 {
191     if (fifo) {
192         if (fifo->buf) {
193             SHFREE(pool, fifo->buf);
194             fifo->buf = NULL;
195         }
196         SHFREE(pool, fifo);
197     }
198 }
199