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