1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4
5 #include "pci.h"
6 #include "vga.h"
7
8 /*
9 * Tvp302[056] Viewpoint Video Interface Palette.
10 * Assumes hooked up to an S3 86C928 or S3 Vision964.
11 */
12 enum {
13 Index = 0x06, /* Index register */
14 Data = 0x07, /* Data register */
15
16 Id = 0x3F, /* ID Register */
17 Tvp3020 = 0x20,
18 Tvp3025 = 0x25,
19 Tvp3026 = 0x26,
20 };
21
22 /*
23 * The following two arrays give read (bit 0) and write (bit 1)
24 * permissions on the direct and index registers. Bits 4 and 5
25 * are for the Tvp3025. The Tvp3020 has only 8 direct registers.
26 */
27 static uchar directreg[32] = {
28 0x33, 0x33, 0x33, 0x33, 0x00, 0x00, 0x33, 0x33,
29 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
30 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
31 0x33, 0x33, 0x11, 0x33, 0x33, 0x33, 0x33, 0x33,
32 };
33
34 static uchar indexreg[64] = {
35 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x00,
36 0x02, 0x02, 0x33, 0x00, 0x00, 0x00, 0x30, 0x30,
37 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
38 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x30, 0x00,
39 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
40 0x33, 0x33, 0x33, 0x33, 0x30, 0x30, 0x30, 0x30,
41 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
42 0x33, 0x30, 0x33, 0x11, 0x11, 0x11, 0x22, 0x11,
43 };
44
45 /*
46 * Check the index register access is valid.
47 * Return the number of direct registers.
48 */
49 static uchar
checkindex(uchar index,uchar access)50 checkindex(uchar index, uchar access)
51 {
52 uchar crt55;
53 static uchar id;
54
55 if(id == 0){
56 crt55 = vgaxi(Crtx, 0x55) & 0xFC;
57 vgaxo(Crtx, 0x55, crt55|((Index>>2) & 0x03));
58 vgao(dacxreg[Index & 0x03], Id);
59
60 id = vgai(dacxreg[Data & 0x03]);
61 vgaxo(Crtx, 0x55, crt55);
62 }
63
64 if(index == 0xFF)
65 return id;
66
67 access &= 0x03;
68 switch(id){
69
70 case Tvp3020:
71 break;
72
73 case Tvp3025:
74 case Tvp3026:
75 access = access<<4;
76 break;
77
78 default:
79 Bprint(&stdout, "%s: unknown chip id - 0x%2.2X\n", tvp3020.name, id);
80 break;
81 }
82
83 if(index > sizeof(indexreg) || (indexreg[index] & access) == 0)
84 error("%s: bad register index - 0x%2.2X\n", tvp3020.name, index);
85
86 return id;
87 }
88
89 static uchar
tvp3020io(uchar reg,uchar data)90 tvp3020io(uchar reg, uchar data)
91 {
92 uchar crt55;
93
94 crt55 = vgaxi(Crtx, 0x55) & 0xFC;
95 vgaxo(Crtx, 0x55, crt55|((reg>>2) & 0x03));
96 vgao(dacxreg[reg & 0x03], data);
97
98 return crt55;
99 }
100
101 uchar
tvp3020i(uchar reg)102 tvp3020i(uchar reg)
103 {
104 uchar crt55, r;
105
106 crt55 = vgaxi(Crtx, 0x55) & 0xFC;
107 vgaxo(Crtx, 0x55, crt55|((reg>>2) & 0x03));
108 r = vgai(dacxreg[reg & 0x03]);
109 vgaxo(Crtx, 0x55, crt55);
110
111 return r;
112 }
113
114 uchar
tvp3020xi(uchar index)115 tvp3020xi(uchar index)
116 {
117 uchar crt55, r;
118
119 checkindex(index, 0x01);
120
121 crt55 = tvp3020io(Index, index);
122 r = vgai(dacxreg[Data & 0x03]);
123 vgaxo(Crtx, 0x55, crt55);
124
125 return r;
126 }
127
128 void
tvp3020o(uchar reg,uchar data)129 tvp3020o(uchar reg, uchar data)
130 {
131 uchar crt55;
132
133 crt55 = tvp3020io(reg, data);
134 vgaxo(Crtx, 0x55, crt55);
135 }
136
137 void
tvp3020xo(uchar index,uchar data)138 tvp3020xo(uchar index, uchar data)
139 {
140 uchar crt55;
141
142 checkindex(index, 0x02);
143
144 crt55 = tvp3020io(Index, index);
145 vgao(dacxreg[Data & 0x03], data);
146 vgaxo(Crtx, 0x55, crt55);
147 }
148
149 static void
options(Vga *,Ctlr * ctlr)150 options(Vga*, Ctlr* ctlr)
151 {
152 ctlr->flag |= Hclk2|Hextsid|Hpvram|Henhanced|Foptions;
153 }
154
155 static void
init(Vga * vga,Ctlr * ctlr)156 init(Vga* vga, Ctlr* ctlr)
157 {
158 ulong grade;
159 char *p;
160
161 /*
162 * Work out the part speed-grade from name. Name can have,
163 * e.g. '-135' on the end for 135MHz part.
164 */
165 grade = 110000000;
166 if(p = strrchr(ctlr->name, '-'))
167 grade = strtoul(p+1, 0, 0) * 1000000;
168
169 /*
170 * If we don't already have a desired pclk,
171 * take it from the mode.
172 * Check it's within range.
173 */
174 if(vga->f[0] == 0)
175 vga->f[0] = vga->mode->frequency;
176 if(vga->f[0] > grade)
177 error("%s: invalid pclk - %ld\n", ctlr->name, vga->f[0]);
178
179 /*
180 * Determine whether to use clock-doubler or not.
181 */
182 if(vga->f[0] > 85000000){
183 vga->f[0] /= 2;
184 resyncinit(vga, ctlr, Uclk2, 0);
185 }
186
187 ctlr->flag |= Finit;
188 }
189
190 static void
load(Vga * vga,Ctlr * ctlr)191 load(Vga* vga, Ctlr* ctlr)
192 {
193 uchar x;
194
195 /*
196 * Input Clock Selection:
197 * VGA CLK0
198 * enhanced CLK1
199 * doubled if necessary.
200 */
201 x = 0x00;
202 if(ctlr->flag & Uenhanced)
203 x |= 0x01;
204 if(ctlr->flag & Uclk2)
205 x |= 0x10;
206 tvp3020xo(0x1A, x);
207
208 /*
209 * Output Clock Selection:
210 * VGA default VGA
211 * enhanced RCLK=SCLK=/8, VCLK/4
212 */
213 x = 0x3E;
214 if(ctlr->flag & Uenhanced)
215 x = 0x53;
216 tvp3020xo(0x1B, x);
217
218 /*
219 * Auxiliary Control:
220 * default settings - self-clocked, palette graphics, no zoom
221 * Colour Key Control:
222 * default settings - pointing to palette graphics
223 * Mux Control Register 1:
224 * pseudo colour
225 */
226 tvp3020xo(0x29, 0x09);
227 tvp3020xo(0x38, 0x10);
228 tvp3020xo(0x18, 0x80);
229
230 /*
231 * Mux Control Register 2:
232 * VGA default VGA
233 * enhanced 8-bpp, 8:1 mux, 64-bit pixel-bus width
234 */
235 x = 0x98;
236 if(ctlr->flag & Uenhanced){
237 if(vga->mode->z == 8)
238 x = 0x1C;
239 else if(vga->mode->z == 1)
240 x = 0x04;
241 }
242 tvp3020xo(0x19, x);
243
244 /*
245 * General Control:
246 * output sync polarity
247 * It's important to set this properly and to turn off the
248 * VGA controller H and V syncs. Can't be set in VGA mode.
249 */
250 x = 0x00;
251 if((vga->misc & 0x40) == 0)
252 x |= 0x01;
253 if((vga->misc & 0x80) == 0)
254 x |= 0x02;
255 tvp3020xo(0x1D, x);
256 vga->misc |= 0xC0;
257 vgao(MiscW, vga->misc);
258
259 /*
260 * Select the DAC via the General Purpose I/O
261 * Register and Pins.
262 * Guesswork by looking at register dumps.
263 */
264 tvp3020xo(0x2A, 0x1F);
265 if(ctlr->flag & Uenhanced)
266 x = 0x1D;
267 else
268 x = 0x1C;
269 tvp3020xo(0x2B, x);
270
271 ctlr->flag |= Fload;
272 }
273
274 static void
dump(Vga *,Ctlr * ctlr)275 dump(Vga*, Ctlr* ctlr)
276 {
277 uchar access;
278 int i;
279
280 access = 0x01;
281 if(checkindex(0x00, 0x01) != Tvp3020)
282 access <<= 4;
283
284 printitem(ctlr->name, "direct");
285 for(i = 0; i < 8; i++){
286 if(directreg[i] & access)
287 printreg(tvp3020i(i));
288 else
289 printreg(0xFF);
290 }
291
292 printitem(ctlr->name, "index");
293 for(i = 0; i < sizeof(indexreg); i++){
294 if(indexreg[i] & access)
295 printreg(tvp3020xi(i));
296 else
297 printreg(0xFF);
298 }
299 }
300
301 Ctlr tvp3020 = {
302 "tvp3020", /* name */
303 0, /* snarf */
304 options, /* options */
305 init, /* init */
306 load, /* load */
307 dump, /* dump */
308 };
309