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 Mach32. Some hope.
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
	Advfunc		= 0x4AE8,	/* Advanced Function Control Register */
20
	Clocksel	= 0x4AEE,	/* Clock Select Register */
21
	Misc		= 0x36EE,	/* Miscellaneous Register */
22
	Membndry	= 0x42EE,	/* Memory Boundary Register */
23
	Memcfg		= 0x5EEE,	/* Memory Control Register */
24
};
25
 
26
typedef struct {
27
	ushort	advfunc;
28
	ushort	clocksel;
29
	ushort	misc;
30
	ushort	membndry;
31
	ushort	memcfg;
32
} Mach32;
33
 
34
/*
35
 * There are a number of possible clock generator chips for these
36
 * boards, and I don't know how to find out which is installed, other
37
 * than by looking at the board. So, pick a subset that will work for
38
 * all.
39
 */
40
typedef struct {
41
	ulong	frequency;
42
	uchar	b8;			/* <6> - divide by 2 */
43
	uchar	b9;			/* <1> - bit <3> of frequency index */
44
	uchar	be;			/* <4> - bit <2> of frequency index */
45
	uchar	misc;			/* <3:2> - bits <1:0> of frequency index */
46
} Clock;
47
 
48
static Clock clocks[] = {
49
	{  VgaFreq0,	0x40, 0x02, 0x00, 0x00, },
50
	{  32000000,	0x00, 0x00, 0x10, 0x04, },
51
	{  40000000,	0x00, 0x02, 0x10, 0x00, },
52
	{  44900000,	0x00, 0x02, 0x00, 0x0C, },
53
	{  65000000,	0x00, 0x02, 0x10, 0x0C, },
54
	{  75000000,	0x00, 0x02, 0x10, 0x08, },
55
	{	  0, },
56
};
57
 
58
static ulong atix;
59
 
60
static uchar
61
atixi(uchar index)
62
{
63
	outportb(atix, index);
64
	return inportb(atix+1);
65
}
66
 
67
static void
68
atixo(uchar index, uchar data)
69
{
70
	outportw(atix, (data<<8)|index);
71
}
72
 
73
static void
74
atixinit(Vga* vga, Ctlr*)
75
{
76
	uchar b;
77
	Mach32 *mach32;
78
 
79
	/*
80
	 * We could try to read in a part of the BIOS and try to determine
81
	 * the extended register address, but since we can't determine the offset value,
82
	 * we'll just have to assume the defaults all round.
83
	 */
84
	atix = 0x1CE;
85
 
86
	/*
87
	 * Unlock the ATI Extended Registers.
88
	 * We leave them unlocked from now on.
89
	 * Why does this chip have so many
90
	 * lock bits?
91
	 */
92
	if((b = atixi(0xB8)) & 0x3F)
93
		atixo(0xB8, b & 0xC0);
94
	b = atixi(0xAB);
95
	atixo(0xAB, b & ~0x18);
96
	atixo(0xB4, 0x00);
97
	b = atixi(0xB9);
98
	atixo(0xB9, b & ~0x80);
99
	b = atixi(0xBE);
100
	atixo(0xBE, b|0x09);
101
 
102
	if(vga->private == 0)
103
		vga->private = alloc(sizeof(mach32));
104
}
105
 
106
static void
107
snarf(Vga* vga, Ctlr* ctlr)
108
{
109
	int i;
110
	Mach32 *mach32;
111
 
112
	atixinit(vga, ctlr);
113
	for(i = 0xA0; i < 0xC0; i++)
114
		vga->crt[i] = atixi(i);
115
 
116
	mach32 = vga->private;
117
	mach32->advfunc = inportw(Advfunc);
118
	mach32->clocksel = inportw(Clocksel);
119
	mach32->misc = inportw(Misc);
120
	mach32->membndry = inportw(Membndry);
121
	mach32->memcfg = inportw(Memcfg);
122
 
123
	/*
124
	 * Memory size.
125
	 */
126
	switch((mach32->misc>>2) & 0x03){
127
 
128
	case 0:
129
		vga->vmz = 512*1024;
130
		break;
131
 
132
	case 1:
133
		vga->vmz = 1024*1024;
134
		break;
135
 
136
	case 2:
137
		vga->vmz = 2*1024*1024;
138
		break;
139
 
140
	case 3:
141
		vga->vmz = 4*1024*1024;
142
		break;
143
	}
144
 
145
	ctlr->flag |= Fsnarf;
146
}
147
 
148
static void
149
options(Vga*, Ctlr* ctlr)
150
{
151
	ctlr->flag |= Foptions;
152
}
153
 
154
static void
155
init(Vga* vga, Ctlr* ctlr)
156
{
157
	Clock *clockp;
158
	Mode *mode;
159
 
160
	mode = vga->mode;
161
 
162
	if(vga->f[0] == 0)
163
		vga->f[0] = vga->mode->frequency;
164
	for(clockp = clocks; clockp->frequency; clockp++){
165
		if(clockp->frequency > vga->f[0]+100000)
166
			continue;
167
		if(clockp->frequency > vga->f[0]-100000)
168
			break;
169
	}
170
	if(clockp->frequency == 0)
171
		error("%s: no suitable clock for %lud\n",
172
			ctlr->name, vga->f[0]);
173
 
174
	vga->crt[0xB0] &= 0xDA;
175
	vga->crt[0xB1] &= 0x87;
176
	vga->crt[0xB5] &= 0x7E;
177
	vga->crt[0xB6] &= 0xE2;
178
	vga->crt[0xB3] &= 0xAF;
179
	vga->crt[0xA6] &= 0xFE;
180
	vga->crt[0xA7] &= 0xF4;
181
 
182
	/*
183
	 * 256-colour linear addressing.
184
	 */
185
	if(mode->z == 8){
186
		vga->graphics[0x05] = 0x00;
187
		vga->attribute[0x10] &= ~0x40;
188
		vga->crt[0x13] = (mode->x/8)/2;
189
		vga->crt[0x14] = 0x00;
190
		vga->crt[0x17] = 0xE3;
191
 
192
		vga->crt[0xB0] |= 0x20;
193
		vga->crt[0xB6] |= 0x04;
194
	}
195
	vga->attribute[0x11] = 0x00;
196
	vga->crt[0xB6] |= 0x01;
197
	vga->crt[0xBE] &= ~0x04;
198
 
199
	/*
200
	 * Do the clock index bits.
201
	 */
202
	vga->crt[0xB9] &= 0xFD;
203
	vga->crt[0xB8] &= 0x3F;
204
	vga->crt[0xBE] &= 0xE5;
205
 
206
	vga->crt[0xB8] |= clockp->b8;
207
	vga->crt[0xB9] |= clockp->b9;
208
	vga->crt[0xBE] |= clockp->be;
209
	vga->misc |= clockp->misc;
210
 
211
	if(vga->mode->interlace == 'v')
212
		vga->crt[0xBE] |= 0x02;
213
 
214
	/*
215
	 * Turn off 128Kb CPU address bit so
216
	 * we only have a 64Kb aperture at 0xA0000.
217
	 */
218
	vga->crt[0xBD] &= ~0x04;
219
 
220
	ctlr->flag |= Finit;
221
}
222
 
223
static void
224
load(Vga* vga, Ctlr* ctlr)
225
{
226
	ushort x;
227
 
228
	/*
229
	 * Make sure we are in VGA mode,
230
	 * and that we have access to all the video memory through
231
	 * the 64Kb VGA aperture by disabling and linear aperture
232
	 * and memory boundary.
233
	 */
234
	outportw(Clocksel, 0x0000);
235
	x = inportw(Memcfg) & ~0x0003;
236
	outportw(Memcfg, x);
237
	outportw(Membndry, 0x0000);
238
 
239
	atixo(0xB0, vga->crt[0xB0]);
240
	atixo(0xB1, vga->crt[0xB1]);
241
	atixo(0xB5, vga->crt[0xB5]);
242
	atixo(0xB6, vga->crt[0xB6]);
243
	atixo(0xB3, vga->crt[0xB3]);
244
	atixo(0xA6, vga->crt[0xA6]);
245
	atixo(0xA7, vga->crt[0xA7]);
246
	atixo(0xB8, vga->crt[0xB8]);
247
	atixo(0xB9, vga->crt[0xB9]);
248
	atixo(0xBE, vga->crt[0xBE]);
249
	vgao(MiscW, vga->misc);
250
 
251
	ctlr->flag |= Fload;
252
}
253
 
254
static void
255
dump(Vga* vga, Ctlr* ctlr)
256
{
257
	int i;
258
	Mach32 *mach32;
259
 
260
	printitem(ctlr->name, "ATIX");
261
	for(i = 0xA0; i < 0xC0; i++)
262
		printreg(vga->crt[i]);
263
 
264
	if((mach32 = vga->private) == 0)
265
		return;
266
 
267
	printitem(ctlr->name, "ADVFUNC");
268
	Bprint(&stdout, "%.4ux\n", mach32->advfunc);
269
	printitem(ctlr->name, "CLOCKSEL");
270
	Bprint(&stdout, "%.4ux\n", mach32->clocksel);
271
	printitem(ctlr->name, "MISC");
272
	Bprint(&stdout, "%.4ux\n", mach32->misc);
273
	printitem(ctlr->name, "MEMBNDRY");
274
	Bprint(&stdout, "%.4ux\n", mach32->membndry);
275
	printitem(ctlr->name, "MEMCFG");
276
	Bprint(&stdout, "%.4ux\n", mach32->memcfg);
277
}
278
 
279
Ctlr mach32 = {
280
	"mach32",			/* name */
281
	snarf,				/* snarf */
282
	options,			/* options */
283
	init,				/* init */
284
	load,				/* load */
285
	dump,				/* dump */
286
};