Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include <u.h>
2
#include <libc.h>
3
#include <bio.h>
4
 
5
#include "pci.h"
6
#include "vga.h"
7
 
8
/*
9
 * ATI Mach64. Some hope. Kind of like a Mach32.
10
 * No support for accelerator so can only do up to 1024x768.
11
 *
12
 * All ATI Extended Registers are addressed using the modified index
13
 *	index = (0x02<<6)|(index & 0x3F);
14
 * so registers 0x00->0x3F map to 0x80->0xBF, but we will only ever
15
 * look at a few in the range 0xA0->0xBF. In this way we can stash
16
 * them in the vga->crt[] array.
17
 */
18
enum {
19
	Configcntl	= 0x6AEC,	/* Configuration control */
20
	Configstat	= 0x72EC,	/* Configuration status */
21
	Memcntl		= 0x52EC,	/* Memory control */
22
	Scratch1	= 0x46EC,	/* Scratch Register (BIOS info) */
23
};
24
 
25
typedef struct {
26
	ulong	configcntl;
27
	ulong	configstat;
28
	ulong	memcntl;
29
	ulong	scratch1;
30
} Mach64;
31
 
32
/*
33
 * There are a number of possible clock generator chips for these
34
 * boards. We can divide any frequency by 2 (bit<6> of b8).
35
 */
36
typedef struct {
37
	ulong	frequency;
38
	uchar	be;			/* <4> - bit<3> of frequency index */
39
	uchar	b9;			/* <1> - bit<2> of frequency index */
40
	uchar	genmo;			/* <3:2> - bits <1:0> of frequency index */
41
} Pclk;
42
 
43
enum {
44
	Npclkx		= 16,		/* number of clock entries per table */
45
};
46
 
47
/*
48
 * ATI18811-0
49
 */
50
static Pclk ati188110[Npclkx] = {
51
	{  42950000, 0x00, 0x00, 0x00 },
52
	{  48770000, 0x00, 0x00, 0x04 },
53
	{  92400000, 0x00, 0x00, 0x08 },
54
	{  36000000, 0x00, 0x00, 0x0C },
55
	{  50350000, 0x00, 0x02, 0x00 },
56
	{  56640000, 0x00, 0x02, 0x04 },
57
	{ 	  0, 0x00, 0x02, 0x08 },
58
	{  44900000, 0x00, 0x02, 0x0C },
59
	{  30240000, 0x10, 0x00, 0x00 },
60
	{  32000000, 0x10, 0x00, 0x04 },
61
	{ 110000000, 0x10, 0x00, 0x08 },
62
	{  80000000, 0x10, 0x00, 0x0C },
63
	{  39910000, 0x10, 0x02, 0x00 },
64
	{  44900000, 0x10, 0x02, 0x04 },
65
	{  75000000, 0x10, 0x02, 0x08 },
66
	{  65000000, 0x10, 0x02, 0x0C },
67
};
68
 
69
/*
70
 * ATI18811-1, ATI18811-2
71
 * PCLK_TABLE = 0 in Mach64 speak.
72
 */
73
static Pclk ati188111[Npclkx] = {
74
	{ 100000000, 0x00, 0x00, 0x00 },
75
	{ 126000000, 0x00, 0x00, 0x04 },
76
	{  92400000, 0x00, 0x00, 0x08 },
77
	{  36000000, 0x00, 0x00, 0x0C },
78
	{  50350000, 0x00, 0x02, 0x00 },
79
	{  56640000, 0x00, 0x02, 0x04 },
80
	{ 	  0, 0x00, 0x02, 0x08 },
81
	{  44900000, 0x00, 0x02, 0x0C },
82
	{ 135000000, 0x10, 0x00, 0x00 },
83
	{  32000000, 0x10, 0x00, 0x04 },
84
	{ 110000000, 0x10, 0x00, 0x08 },
85
	{  80000000, 0x10, 0x00, 0x0C },
86
	{  39910000, 0x10, 0x02, 0x00 },
87
	{  44900000, 0x10, 0x02, 0x04 },
88
	{  75000000, 0x10, 0x02, 0x08 },
89
	{  65000000, 0x10, 0x02, 0x0C },
90
};
91
 
92
/*
93
 * ATI18818
94
 * The first four entries are programmable and the default
95
 * settings are either those below or those below divided by 2
96
 * (PCLK_TABLE = 1 and PCLK_TABLE = 2 respectively in Mach64
97
 * speak).
98
 */
99
static Pclk ati18818[Npclkx] = {
100
	{  50350000, 0x00, 0x00, 0x00 },
101
	{  56640000, 0x00, 0x00, 0x04 },
102
	{  63000000, 0x00, 0x00, 0x08 },
103
	{  72000000, 0x00, 0x00, 0x0C },
104
	{  40000000, 0x00, 0x02, 0x00 },
105
	{  44900000, 0x00, 0x02, 0x04 },
106
	{  49500000, 0x00, 0x02, 0x08 },
107
	{  50000000, 0x00, 0x02, 0x0C },
108
	{ 	  0, 0x10, 0x00, 0x00 },
109
	{ 110000000, 0x10, 0x00, 0x04 },
110
	{ 126000000, 0x10, 0x00, 0x08 },
111
	{ 135000000, 0x10, 0x00, 0x0C },
112
	{ 	  0, 0x10, 0x02, 0x00 },
113
	{  80000000, 0x10, 0x02, 0x04 },
114
	{  75000000, 0x10, 0x02, 0x08 },
115
	{  65000000, 0x10, 0x02, 0x0C },
116
};
117
 
118
static Pclk *pclkp;			/* which clock chip we are using */
119
static ulong atix;			/* index to extended regsiters */
120
 
121
static uchar
122
atixi(uchar index)
123
{
124
	outportb(atix, index);
125
	return inportb(atix+1);
126
}
127
 
128
static void
129
atixo(uchar index, uchar data)
130
{
131
	outportw(atix, (data<<8)|index);
132
}
133
 
134
static void
135
atixinit(Vga* vga, Ctlr*)
136
{
137
	uchar b;
138
 
139
	/*
140
	 * Set the I/O address and offset for the ATI
141
	 * extended registers to something we know about.
142
	 */
143
	if(atix == 0){
144
		outportw(Grx, (0xCE<<8)|0x50);
145
		outportw(Grx, (0x81<<8)|0x51);
146
		atix = 0x1CE;
147
	}
148
 
149
	/*
150
	 * Unlock the ATI Extended Registers.
151
	 * We leave them unlocked from now on.
152
	 * Why does this chip have so many
153
	 * lock bits?
154
	 */
155
	if((b = atixi(0xB8)) & 0x3F)
156
		atixo(0xB8, b & 0xC0);
157
	b = atixi(0xAB);
158
	atixo(0xAB, b & ~0x18);
159
	atixo(0xB4, 0x00);
160
	b = atixi(0xB9);
161
	atixo(0xB9, b & ~0x80);
162
	b = atixi(0xBE);
163
	atixo(0xBE, b|0x09);
164
 
165
	if(vga->private == 0)
166
		vga->private = alloc(sizeof(Mach64));
167
}
168
 
169
static void
170
snarf(Vga* vga, Ctlr* ctlr)
171
{
172
	int i;
173
	Mach64 *mach64;
174
 
175
	atixinit(vga, ctlr);
176
	for(i = 0xA0; i < 0xC0; i++)
177
		vga->crt[i] = atixi(i);
178
 
179
	mach64 = vga->private;
180
	mach64->configcntl = inportl(Configcntl);
181
	mach64->configstat = inportl(Configstat);
182
	mach64->memcntl = inportl(Memcntl);
183
	mach64->scratch1 = inportl(Scratch1);
184
 
185
	/*
186
	 * Memory size.
187
	 */
188
	switch(mach64->memcntl & 0x07){
189
 
190
	case 0:
191
		vga->vmz = 512*1024;
192
		break;
193
 
194
	case 1:
195
		vga->vmz = 1024*1024;
196
		break;
197
 
198
	case 2:
199
		vga->vmz = 2*1024*1024;
200
		break;
201
 
202
	case 3:
203
		vga->vmz = 4*1024*1024;
204
		break;
205
 
206
	case 4:
207
		vga->vmz = 6*1024*1024;
208
		break;
209
 
210
	case 5:
211
		vga->vmz = 8*1024*1024;
212
		break;
213
	}
214
 
215
	ctlr->flag |= Fsnarf;
216
}
217
 
218
static void
219
init(Vga* vga, Ctlr* ctlr)
220
{
221
	Mode *mode;
222
	int f, divisor, index;
223
 
224
	mode = vga->mode;
225
 
226
	/*
227
	 * Must somehow determine which clock chip to use here.
228
	 * For now, punt and assume ATI18818.
229
	 */
230
	pclkp = ati18818;
231
	if(pclkp == 0)
232
		error("%s: can't determine clock chip\n", ctlr->name);
233
 
234
	if(vga->f[0] == 0)
235
		vga->f[0] = vga->mode->frequency;
236
 
237
	/*
238
	 * Find a clock frequency close to what we want.
239
	 * 'Close' is within 1MHz.
240
	 */
241
	for(divisor = 0, index = 0; index < Npclkx; index++, divisor = 0){
242
		divisor = 1;
243
		f = pclkp[index].frequency/divisor;
244
		if(f < vga->f[0]+1000000 && f >= vga->f[0]-1000000)
245
			break;
246
 
247
		divisor = 2;
248
		f /= divisor;
249
		if(f < vga->f[0]+1000000 && f >= vga->f[0]-1000000)
250
			break;
251
	}
252
	if(divisor == 0)
253
		error("%s: no suitable clock for %lud\n",
254
			ctlr->name, vga->f[0]);
255
 
256
	vga->d[0] = divisor;
257
	vga->i[0] = index;
258
 
259
	vga->crt[0xB0] &= 0xDA;
260
	vga->crt[0xB1] &= 0x87;
261
	vga->crt[0xB5] &= 0x7E;
262
	vga->crt[0xB6] &= 0xE2;
263
	vga->crt[0xB3] &= 0xAF;
264
	vga->crt[0xA6] &= 0xFE;
265
	vga->crt[0xA7] &= 0xF4;
266
 
267
	/*
268
	 * 256-colour linear addressing.
269
	 */
270
	if(mode->z == 8){
271
		vga->graphics[0x05] = 0x00;
272
		vga->attribute[0x10] &= ~0x40;
273
		vga->crt[0x13] = (mode->x/8)/2;
274
		vga->crt[0x14] = 0x00;
275
		vga->crt[0x17] = 0xE3;
276
 
277
		vga->crt[0xB0] |= 0x20;
278
		vga->crt[0xB6] |= 0x04;
279
	}
280
	vga->attribute[0x11] = 0x00;
281
	vga->crt[0xB6] |= 0x01;
282
	vga->crt[0xBE] &= ~0x04;
283
 
284
	/*
285
	 * Do the clock index bits.
286
	 */
287
	vga->crt[0xB8] &= 0x3F;
288
	vga->crt[0xB9] &= 0xFD;
289
	vga->crt[0xBE] &= 0xE5;
290
 
291
	if(vga->d[0] == 2)
292
		vga->crt[0xB8] |= 0x40;
293
	vga->crt[0xB9] |= pclkp[vga->i[0]].b9;
294
	vga->crt[0xBE] |= pclkp[vga->i[0]].be;
295
	vga->misc |= pclkp[vga->i[0]].genmo;
296
 
297
	if(vga->mode->interlace == 'v')
298
		vga->crt[0xBE] |= 0x02;
299
 
300
	/*
301
	 * Turn off 128Kb CPU address bit so
302
	 * we only have a 64Kb aperture at 0xA0000.
303
	 */
304
	vga->crt[0xBD] &= ~0x04;
305
 
306
	ctlr->type = mach32.name;
307
 
308
	/*
309
	 * The Mach64 can only address 1Mb in VGA mode
310
	 */
311
	vga->vmz = 1*1024*1024;
312
 
313
	ctlr->flag |= Finit;
314
}
315
 
316
static void
317
load(Vga* vga, Ctlr* ctlr)
318
{
319
	/*
320
	 * We should probably do something here to make sure we that we
321
	 * have access to all the video memory through the 64Kb VGA aperture
322
	 * by disabling and linear aperture and memory boundary and then
323
	 * enabling the VGA controller.
324
	 * But for now, let's just assume it's ok, the Mach64 documentation
325
	 * is just as clear as the Mach32 documentation.
326
	 */
327
	atixo(0xB0, vga->crt[0xB0]);
328
	atixo(0xB1, vga->crt[0xB1]);
329
	atixo(0xB5, vga->crt[0xB5]);
330
	atixo(0xB6, vga->crt[0xB6]);
331
	atixo(0xB3, vga->crt[0xB3]);
332
	atixo(0xA6, vga->crt[0xA6]);
333
	atixo(0xA7, vga->crt[0xA7]);
334
	atixo(0xB8, vga->crt[0xB8]);
335
	atixo(0xB9, vga->crt[0xB9]);
336
	atixo(0xBE, vga->crt[0xBE]);
337
	vgao(MiscW, vga->misc);
338
 
339
	ctlr->flag |= Fload;
340
}
341
 
342
static void
343
dump(Vga* vga, Ctlr* ctlr)
344
{
345
	int i;
346
	Mach64 *mach64;
347
 
348
	printitem(ctlr->name, "ATIX");
349
	for(i = 0xA0; i < 0xC0; i++)
350
		printreg(vga->crt[i]);
351
 
352
	if((mach64 = vga->private) == 0)
353
		return;
354
 
355
	printitem(ctlr->name, "CONFIGCNTL");
356
	Bprint(&stdout, "%.8lux\n", mach64->configcntl);
357
	printitem(ctlr->name, "CONFIGSTAT");
358
	Bprint(&stdout, "%.8lux\n", mach64->configstat);
359
	printitem(ctlr->name, "MEMCNTL");
360
	Bprint(&stdout, "%.8lux\n", mach64->memcntl);
361
	printitem(ctlr->name, "SCRATCH1");
362
	Bprint(&stdout, "%.8lux\n", mach64->scratch1);
363
}
364
 
365
Ctlr mach64 = {
366
	"mach64",			/* name */
367
	snarf,				/* snarf */
368
	0,				/* options */
369
	init,				/* init */
370
	load,				/* load */
371
	dump,				/* dump */
372
};