1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4
5 #include "pci.h"
6 #include "vga.h"
7
8 /*
9 * IBM RGB524.
10 * 170/220MHz High Performance Palette DAC.
11 *
12 * Assumes hooked up to an S3 Vision96[48].
13 */
14 enum {
15 IndexLo = 0x00,
16 IndexHi = 0x01,
17 Data = 0x02,
18 IndexCtl = 0x03,
19 };
20
21 enum { /* index registers */
22 MiscClock = 0x02,
23 PixelFormat = 0x0A,
24 PLLControl1 = 0x10,
25 PLLControl2 = 0x11,
26 PLLReference = 0x14,
27 Frequency0 = 0x20,
28 MiscControl1 = 0x70,
29 MiscControl2 = 0x71,
30 };
31
32 static uchar
setrs2(void)33 setrs2(void)
34 {
35 uchar rs2;
36
37 rs2 = vgaxi(Crtx, 0x55);
38 vgaxo(Crtx, 0x55, (rs2 & 0xFC)|0x01);
39
40 return rs2;
41 }
42
43 static uchar
rgb524xi(int index)44 rgb524xi(int index)
45 {
46 outportb(dacxreg[IndexLo], index & 0xFF);
47 outportb(dacxreg[IndexHi], (index>>8) & 0xFF);
48
49 return inportb(dacxreg[Data]);
50 }
51
52 static void
rgb524xo(int index,uchar data)53 rgb524xo(int index, uchar data)
54 {
55 outportb(dacxreg[IndexLo], index & 0xFF);
56 outportb(dacxreg[IndexHi], (index>>8) & 0xFF);
57
58 outportb(dacxreg[Data], data);
59 }
60
61 static void
restorers2(uchar rs2)62 restorers2(uchar rs2)
63 {
64 vgaxo(Crtx, 0x55, rs2);
65 }
66
67 static void
clock(Vga * vga,Ctlr * ctlr)68 clock(Vga* vga, Ctlr* ctlr)
69 {
70 if(vga->f[0] >= 16250000 && vga->f[0] <= 32000000){
71 vga->f[0] = (vga->f[0]/250000)*250000;
72 vga->d[0] = (4*vga->f[0])/1000000 - 65;
73 }
74 else if(vga->f[0] >= 32500000 && vga->f[0] <= 64000000){
75 vga->f[0] = (vga->f[0]/500000)*500000;
76 vga->d[0] = 0x40|((2*vga->f[0])/1000000 - 65);
77 }
78 else if(vga->f[0] >= 65000000 && vga->f[0] <= 128000000){
79 vga->f[0] = (vga->f[0]/1000000)*1000000;
80 vga->d[0] = 0x80|(vga->f[0]/1000000 - 65);
81 }
82 else if(vga->f[0] >= 130000000 && vga->f[0] <= 220000000){
83 vga->f[0] = (vga->f[0]/2000000)*2000000;
84 vga->d[0] = 0xC0|((vga->f[0]/2)/1000000 - 65);
85 }
86 else
87 error("%s: pclk %lud out of range\n",
88 ctlr->name, vga->f[0]);
89 }
90
91 static void
init(Vga * vga,Ctlr * ctlr)92 init(Vga* vga, Ctlr* ctlr)
93 {
94 ulong pclk;
95 char *p;
96
97 /*
98 * Part comes in -170 and -220MHz speed-grades.
99 */
100 pclk = 170000000;
101 if(p = strrchr(ctlr->name, '-'))
102 pclk = strtoul(p+1, 0, 0) * 1000000;
103
104 /*
105 * If we don't already have a desired pclk,
106 * take it from the mode.
107 * Check it's within range.
108 */
109 if(vga->f[0] == 0)
110 vga->f[0] = vga->mode->frequency;
111 if(vga->f[0] > pclk)
112 error("%s: invalid pclk - %ld\n", ctlr->name, vga->f[0]);
113
114 /*
115 * Determine whether to use clock-doubler or not.
116 */
117 if((ctlr->flag & Uclk2) == 0 && vga->mode->z == 8)
118 resyncinit(vga, ctlr, Uclk2, 0);
119
120 /*
121 * Clock bits. If the desired video clock is
122 * one of the two standard VGA clocks it can just be
123 * set using bits <3:2> of vga->misc, otherwise we
124 * need to programme the PLL.
125 */
126 vga->misc &= ~0x0C;
127 if(vga->mode->z == 8 || (vga->f[0] != VgaFreq0 && vga->f[0] != VgaFreq1)){
128 /*
129 * Initialise the PLL parameters.
130 * Use internal FS3 fixed-reference divider.
131 */
132 clock(vga, ctlr);
133 vga->i[0] = 0x03;
134 }
135 else if(vga->f[0] == VgaFreq0)
136 vga->i[0] = 0;
137 else if(vga->f[0] == VgaFreq1){
138 vga->misc |= 0x04;
139 vga->i[0] = 1;
140 }
141
142 ctlr->flag |= Finit;
143 }
144
145 static void
load(Vga * vga,Ctlr * ctlr)146 load(Vga* vga, Ctlr* ctlr)
147 {
148 uchar mc2, rs2, x;
149 char *val;
150 int f;
151
152 rs2 = setrs2();
153
154 /*
155 * Set VgaFreq[01].
156 */
157 rgb524xo(PLLControl1, 0x00);
158 rgb524xo(Frequency0, 0x24);
159 rgb524xo(Frequency0+1, 0x30);
160
161 if(val = dbattr(vga->attr, "rgb524refclk")){
162 f = strtol(val, 0, 0);
163 if(f > 1000000)
164 f /= 1000000;
165 rgb524xo(PLLReference, f/2);
166 }
167
168 /*
169 * Enable pixel programming and clock divide
170 * factor.
171 */
172 x = rgb524xi(MiscClock) & ~0x0E;
173 x |= 0x01;
174 if(ctlr->flag & Uclk2)
175 x |= 0x02;
176 rgb524xo(MiscClock, x);
177
178 if(vga->mode->z == 1)
179 rgb524xo(PixelFormat, 0x02);
180 else if(vga->mode->z == 8)
181 rgb524xo(PixelFormat, 0x03);
182
183 x = rgb524xi(MiscControl1) & ~0x41;
184 x |= 0x01;
185 rgb524xo(MiscControl1, x);
186
187 mc2 = rgb524xi(MiscControl2) & ~0x41;
188 vga->crt[0x22] &= ~0x08;
189 if(vga->i[0] == 3){
190 rgb524xo(Frequency0+3, vga->d[0]);
191 rgb524xo(PLLControl1, 0x02);
192 rgb524xo(PLLControl2, vga->i[0]);
193 mc2 |= 0x41;
194 vga->crt[0x22] |= 0x08;
195 }
196 rgb524xo(MiscControl2, mc2);
197 vgaxo(Crtx, 0x22, vga->crt[0x22]);
198
199 restorers2(rs2);
200 ctlr->flag |= Fload;
201 }
202
203 static void
dump(Vga *,Ctlr * ctlr)204 dump(Vga*, Ctlr* ctlr)
205 {
206 uchar rs2, r, x[256];
207 char buf[32];
208 int df, i, maxf, vcodc, vf;
209
210 rs2 = setrs2();
211 printitem(ctlr->name, "index00");
212 for(i = 0x00; i < 0x0F; i++){
213 x[i] = rgb524xi(i);
214 printreg(x[i]);
215 }
216 printitem(ctlr->name, "index10");
217 for(i = 0x10; i < 0x17; i++){
218 x[i] = rgb524xi(i);
219 printreg(x[i]);
220 }
221 printitem(ctlr->name, "index20");
222 for(i = 0x20; i < 0x30; i++){
223 x[i] = rgb524xi(i);
224 printreg(x[i]);
225 }
226 printitem(ctlr->name, "index30");
227 for(i = 0x30; i < 0x37; i++){
228 x[i] = rgb524xi(i);
229 printreg(x[i]);
230 }
231 printitem(ctlr->name, "index40");
232 for(i = 0x40; i < 0x49; i++){
233 x[i] = rgb524xi(i);
234 printreg(x[i]);
235 }
236 printitem(ctlr->name, "index60");
237 for(i = 0x60; i < 0x63; i++){
238 x[i] = rgb524xi(i);
239 printreg(x[i]);
240 }
241 printitem(ctlr->name, "index70");
242 for(i = 0x70; i < 0x73; i++){
243 x[i] = rgb524xi(i);
244 printreg(x[i]);
245 }
246 printitem(ctlr->name, "index8E");
247 for(i = 0x8E; i < 0x92; i++){
248 x[i] = rgb524xi(i);
249 printreg(x[i]);
250 }
251 restorers2(rs2);
252
253 /*
254 * x[0x10] pixel clock frequency selection
255 * 0, 2 for direct programming
256 * x[0x20-0x2F] pixel frequency 0-15
257 */
258 printitem(ctlr->name, "refclk");
259 Bprint(&stdout, "%12ud\n", x[PLLReference]*2*1000000);
260 if((i = (x[0x10] & 0x07)) == 0x00 || i == 0x02){
261 /*
262 * Direct programming, external frequency select.
263 * F[0-4] are probably tied directly to the 2 clock-select
264 * bits in the VGA Misc register.
265 */
266 if(i == 0)
267 maxf = 4;
268 else
269 maxf = 16;
270 for(i = 0; i < maxf; i++){
271 if((r = x[0x20+i]) == 0)
272 continue;
273 sprint(buf, "direct F%X", i);
274 printitem(ctlr->name, buf);
275 df = (r>>6) & 0x03;
276 vcodc = r & 0x3F;
277
278 vf = 0;
279 switch(df){
280 case 0:
281 vf = (vcodc+65)/4;
282 break;
283
284 case 1:
285 vf = (vcodc+65)/2;
286 break;
287
288 case 2:
289 vf = (vcodc+65);
290 break;
291
292 case 3:
293 vf = (vcodc+65)*2;
294 break;
295 }
296 Bprint(&stdout, "%12ud\n", vf);
297 }
298 }
299 }
300
301 Ctlr rgb524 = {
302 "rgb524", /* name */
303 0, /* snarf */
304 0, /* options */
305 init, /* init */
306 load, /* load */
307 dump, /* dump */
308 };
309