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 RGB52x and compatibles.
10 * High Performance Palette DAC.
11 */
12 uchar (*rgb524mnxi)(Vga*, int);
13 void (*rgb524mnxo)(Vga*, int, uchar);
14
15 enum { /* index registers */
16 MiscClock = 0x02,
17 SyncControl = 0x03,
18 HSyncControl = 0x04,
19 PowerMgmnt = 0x05,
20 PaletteControl = 0x07,
21 SYSCLKControl = 0x08,
22 PixelFormat = 0x0A,
23 Pixel8Control = 0x0B,
24 Pixel16Control = 0x0C,
25 Pixel32Control = 0x0E,
26 PLLControl1 = 0x10,
27 PLLControl2 = 0x11,
28 SYSCLKN = 0x15,
29 SYSCLKM = 0x16,
30 M0 = 0x20,
31 N0 = 0x21,
32 MiscControl1 = 0x70,
33 MiscControl2 = 0x71,
34 };
35
36 static void
clock(Vga * vga,Ctlr *,ulong fref,ulong maxpclk)37 clock(Vga* vga, Ctlr*, ulong fref, ulong maxpclk)
38 {
39 int d, mind;
40 ulong df, f, m, n, vrf;
41
42 mind = vga->f[0]+1;
43 for(df = 0; df < 4; df++){
44 for(m = 2; m < 64; m++){
45 for(n = 2; n < 32; n++){
46 f = (fref*(m+65))/n;
47 switch(df){
48 case 0:
49 vrf = fref/(n*2);
50 if(vrf > maxpclk/4 || vrf < 1000000)
51 continue;
52 f /= 8;
53 break;
54 case 1:
55 vrf = fref/(n*2);
56 if(vrf > maxpclk/2 || vrf < 1000000)
57 continue;
58 f /= 4;
59 break;
60 case 2:
61 vrf = fref/(n*2);
62 if(vrf > maxpclk || vrf < 1000000)
63 continue;
64 f /= 2;
65 break;
66 case 3:
67 vrf = fref/n;
68 if(vrf > maxpclk || vrf < 1000000)
69 continue;
70 break;
71 }
72 if(f > maxpclk)
73 continue;
74
75 d = vga->f[0] - f;
76 if(d < 0)
77 d = -d;
78 if(d <= mind){
79 vga->m[0] = m;
80 vga->n[0] = n;
81 vga->d[0] = df;
82 mind = d;
83 }
84 }
85 }
86 }
87 }
88
89 static void
init(Vga * vga,Ctlr * ctlr)90 init(Vga* vga, Ctlr* ctlr)
91 {
92 ulong fref, maxpclk;
93 char *p, *val;
94
95 /*
96 * Part comes in at least a -170MHz speed-grade.
97 */
98 maxpclk = 170000000;
99 if(p = strrchr(ctlr->name, '-'))
100 maxpclk = strtoul(p+1, 0, 0) * 1000000;
101
102 /*
103 * If we don't already have a desired pclk,
104 * take it from the mode.
105 * Check it's within range.
106 */
107 if(vga->f[0] == 0)
108 vga->f[0] = vga->mode->frequency;
109 if(vga->f[0] > maxpclk)
110 error("%s: invalid pclk - %ld\n", ctlr->name, vga->f[0]);
111 if(val = dbattr(vga->attr, "rgb524mnrefclk"))
112 fref = strtol(val, 0, 0);
113 else
114 fref = RefFreq;
115
116 /*
117 * Initialise the PLL parameters.
118 * Use m/n pair 2.
119 */
120 clock(vga, ctlr, fref, maxpclk);
121 vga->i[0] = 2;
122
123 ctlr->flag |= Finit;
124 }
125
126 static void
load(Vga * vga,Ctlr * ctlr)127 load(Vga* vga, Ctlr* ctlr)
128 {
129 char *val;
130 int hsyncdelay, x;
131
132 if(rgb524mnxi == nil && rgb524mnxo == nil)
133 error("%s->load: no access routines\n", ctlr->name);
134
135 /*
136 * Set the m/n values for the desired frequency and
137 * set pixel control to use compatibility mode with
138 * internal frequency select using the specified set
139 * of m/n registers.
140 */
141 rgb524mnxo(vga, M0+vga->i[0]*2, vga->d[0]<<6|vga->m[0]);
142 rgb524mnxo(vga, N0+vga->i[0]*2, vga->n[0]);
143 rgb524mnxo(vga, PLLControl2, vga->i[0]);
144 rgb524mnxo(vga, PLLControl1, 0x03);
145
146 /*
147 * Enable pixel programming in MiscClock;
148 * nothing to do in MiscControl1;
149 * set internal PLL clock and !vga in MiscControl2;
150 */
151 x = rgb524mnxi(vga, MiscClock) & ~0x01;
152 x |= 0x01;
153 rgb524mnxo(vga, MiscClock, x);
154
155 x = rgb524mnxi(vga, MiscControl2) & ~0x41;
156 x |= 0x41;
157 rgb524mnxo(vga, MiscControl2, x);
158
159 /*
160 * Syncs.
161 */
162 x = 0;
163 if(vga->mode->hsync == '+')
164 x |= 0x10;
165 if(vga->mode->vsync == '+')
166 x |= 0x20;
167 rgb524mnxo(vga, SyncControl, x);
168 if(val = dbattr(vga->mode->attr, "hsyncdelay"))
169 hsyncdelay = strtol(val, 0, 0);
170 else switch(vga->mode->z){
171 default:
172 case 8:
173 hsyncdelay = 1;
174 break;
175 case 15:
176 case 16:
177 hsyncdelay = 5;
178 break;
179 case 32:
180 hsyncdelay = 7;
181 break;
182 }
183 rgb524mnxo(vga, HSyncControl, hsyncdelay);
184
185 rgb524mnxo(vga, SYSCLKM, 0x50);
186 rgb524mnxo(vga, SYSCLKN, 0x08);
187 sleep(50);
188 //rgb524mnxo(vga, SYSCLKM, 0x6F);
189 //rgb524mnxo(vga, SYSCLKN, 0x0F);
190 //sleep(500);
191
192 /*
193 * Set the palette for the desired format.
194 * ****NEEDS WORK FOR OTHER THAN 8-BITS****
195 */
196 rgb524mnxo(vga, PaletteControl, 0x00);
197 switch(vga->mode->z){
198 case 8:
199 rgb524mnxo(vga, PixelFormat, 0x03);
200 rgb524mnxo(vga, Pixel8Control, 0x00);
201 break;
202 case 15:
203 rgb524mnxo(vga, PixelFormat, 0x04);
204 rgb524mnxo(vga, Pixel16Control, 0xC4);
205 case 16:
206 rgb524mnxo(vga, PixelFormat, 0x04);
207 rgb524mnxo(vga, Pixel16Control, 0xC6);
208 break;
209 case 32:
210 rgb524mnxo(vga, PixelFormat, 0x06);
211 rgb524mnxo(vga, Pixel32Control, 0x03);
212 break;
213 }
214 }
215
216 static void
dumpclock(Vga *,Ctlr * ctlr,ulong fref,ulong m,ulong n,char * name)217 dumpclock(Vga*, Ctlr* ctlr, ulong fref, ulong m, ulong n, char* name)
218 {
219 ulong df, f;
220
221 df = (m>>6) & 0x03;
222 m &= 0x3F;
223 n &= 0x1F;
224 if(m == 0 || n == 0)
225 return;
226 f = (fref*(m+65))/n;
227 switch(df){
228 case 0:
229 f /= 8;
230 break;
231 case 1:
232 f /= 4;
233 break;
234 case 2:
235 f /= 2;
236 break;
237 case 3:
238 break;
239 }
240 printitem(ctlr->name, name);
241 Bprint(&stdout, "%12lud\n", f);
242 }
243
244 static void
dump(Vga * vga,Ctlr * ctlr)245 dump(Vga* vga, Ctlr* ctlr)
246 {
247 int i;
248 char *val;
249 uchar x[256];
250 ulong fref, fs;
251
252 if(rgb524mnxi == nil && rgb524mnxo == nil)
253 error("%s->dump: no access routines\n", ctlr->name);
254
255 printitem(ctlr->name, "index00");
256 for(i = 0x00; i < 0x0F; i++){
257 x[i] = rgb524mnxi(vga, i);
258 printreg(x[i]);
259 }
260 printitem(ctlr->name, "index10");
261 for(i = 0x10; i < 0x18; i++){
262 x[i] = rgb524mnxi(vga, i);
263 printreg(x[i]);
264 }
265 printitem(ctlr->name, "index20");
266 for(i = 0x20; i < 0x30; i++){
267 x[i] = rgb524mnxi(vga, i);
268 printreg(x[i]);
269 }
270 printitem(ctlr->name, "index30");
271 for(i = 0x30; i < 0x39; i++){
272 x[i] = rgb524mnxi(vga, i);
273 printreg(x[i]);
274 }
275 printitem(ctlr->name, "index40");
276 for(i = 0x40; i < 0x49; i++){
277 x[i] = rgb524mnxi(vga, i);
278 printreg(x[i]);
279 }
280 printitem(ctlr->name, "index60");
281 for(i = 0x60; i < 0x63; i++){
282 x[i] = rgb524mnxi(vga, i);
283 printreg(x[i]);
284 }
285 printitem(ctlr->name, "index70");
286 for(i = 0x70; i < 0x73; i++){
287 x[i] = rgb524mnxi(vga, i);
288 printreg(x[i]);
289 }
290 printitem(ctlr->name, "index8E");
291 for(i = 0x8E; i < 0x92; i++){
292 x[i] = rgb524mnxi(vga, i);
293 printreg(x[i]);
294 }
295
296 if(val = dbattr(vga->attr, "rgb524mnrefclk"))
297 fref = strtol(val, 0, 0);
298 else
299 fref = RefFreq;
300 if(!(x[SYSCLKControl] & 0x04))
301 dumpclock(vga, ctlr, fref, x[0x16], x[0x15], "sysclk");
302 fs = x[PLLControl1] & 0x07;
303 if(fs == 0x01 || fs == 0x03){
304 if(fs == 0x01)
305 i = ((vga->misc>>2) & 0x03)*2;
306 else
307 i = x[PLLControl2] & 0x07;
308 dumpclock(vga, ctlr, fref, x[M0+i*2], x[N0+i*2], "pllclk");
309 }
310 }
311
312 Ctlr rgb524mn = {
313 "rgb524mn", /* name */
314 0, /* snarf */
315 0, /* options */
316 init, /* init */
317 load, /* load */
318 dump, /* dump */
319 };
320