Subversion Repositories planix.SVN

Rev

Details | 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
 * Clocks which require fiddling with the S3 registers
10
 * in order to be loaded.
11
 */
12
static void
13
setcrt42(Vga* vga, Ctlr* ctlr, uchar index)
14
{
15
	trace("%s->clock->setcrt42\n", ctlr->name);
16
 
17
	vgao(MiscW, vga->misc & ~0x0C);
18
	outportb(Crtx+1, 0x00);
19
 
20
	vga->crt[0x42] = (vga->crt[0x42] & 0xF0)|index;
21
	vgao(MiscW, vga->misc);
22
	vgaxo(Crtx, 0x42, vga->crt[0x42]);
23
}
24
 
25
static void
26
icd2061aload(Vga* vga, Ctlr* ctlr)
27
{
28
	ulong sdata;
29
	int i;
30
	uchar crt42;
31
 
32
	trace("%s->clock->icd2061aload\n", ctlr->name);
33
	/*
34
	 * The serial word to be loaded into the icd2061a is
35
	 *	(2<<21)|(vga->i<<17)|((vga->n)<<10)|(vga->p<<7)|vga->d
36
	 * Always select ICD2061A REG2.
37
	 */
38
	sdata = (2<<21)|(vga->i[0]<<17)|((vga->n[0])<<10)|(vga->p[0]<<7)|vga->d[0];
39
 
40
	/*
41
	 * The display should be already off to enable  us to clock the
42
	 * serial data word into either MiscW or Crt42.
43
	 *
44
	 * Set the Misc register to make clock-select-out the contents of
45
	 * register Crt42. Must turn the sequencer off when changing bits
46
	 * <3:2> of Misc. Also, must set Crt42 to 0 before setting <3:2>
47
	 * of Misc due to a hardware glitch.
48
	 */
49
	vgao(MiscW, vga->misc & ~0x0C);
50
	crt42 = vgaxi(Crtx, 0x42) & 0xF0;
51
	outportb(Crtx+1, 0x00);
52
 
53
	vgaxo(Seqx, 0x00, 0x00);
54
	vgao(MiscW, vga->misc|0x0C);
55
	vgaxo(Seqx, 0x00, 0x03);
56
 
57
	/*
58
	 * Unlock the ICD2061A. The unlock sequence is at least 5 low-to-high
59
	 * transitions of CLK with DATA high, followed by a single low-to-high
60
	 * transition of CLK with DATA low.
61
	 * Using Crt42, CLK is bit0, DATA is bit 1. If we used MiscW, they'd
62
	 * be bits 2 and 3 respectively.
63
	 */
64
	outportb(Crtx+1, crt42|0x00);			/* -DATA|-CLK */
65
	outportb(Crtx+1, crt42|0x02);			/* +DATA|-CLK */
66
	for(i = 0; i < 5; i++){
67
		outportb(Crtx+1, crt42|0x03);		/* +DATA|+CLK */
68
		outportb(Crtx+1, crt42|0x02);		/* +DATA|-CLK */
69
	}
70
	outportb(Crtx+1, crt42|0x00);			/* -DATA|-CLK */
71
	outportb(Crtx+1, crt42|0x01);			/* -DATA|+CLK */
72
 
73
	/*
74
	 * Now write the serial data word, framed by a start-bit and a stop-bit.
75
	 * The data is written using a modified Manchester encoding such that a
76
	 * data-bit is sampled on the rising edge of CLK and the complement of
77
	 * the data-bit is sampled on the previous falling edge of CLK.
78
	 */
79
	outportb(Crtx+1, crt42|0x00);			/* -DATA|-CLK (start-bit) */
80
	outportb(Crtx+1, crt42|0x01);			/* -DATA|+CLK */
81
 
82
	for(i = 0; i < 24; i++){			/* serial data word */
83
		if(sdata & 0x01){
84
			outportb(Crtx+1, crt42|0x01);	/* -DATA|+CLK */
85
			outportb(Crtx+1, crt42|0x00);	/* -DATA|-CLK (falling edge) */
86
			outportb(Crtx+1, crt42|0x02);	/* +DATA|-CLK */
87
			outportb(Crtx+1, crt42|0x03);	/* +DATA|+CLK (rising edge) */
88
		}
89
		else {
90
			outportb(Crtx+1, crt42|0x03);	/* +DATA|+CLK */
91
			outportb(Crtx+1, crt42|0x02);	/* +DATA|-CLK (falling edge) */
92
			outportb(Crtx+1, crt42|0x00);	/* -DATA|-CLK */
93
			outportb(Crtx+1, crt42|0x01);	/* -DATA|+CLK (rising edge) */
94
		}
95
		sdata >>= 1;
96
	}
97
 
98
	outportb(Crtx+1, crt42|0x03);			/* +DATA|+CLK (stop-bit) */
99
	outportb(Crtx+1, crt42|0x02);			/* +DATA|-CLK */
100
	outportb(Crtx+1, crt42|0x03);			/* +DATA|+CLK */
101
 
102
	/*
103
	 * We always use REG2 in the ICD2061A.
104
	 */
105
	setcrt42(vga, ctlr, 0x02);
106
}
107
 
108
static void
109
ch9294load(Vga* vga, Ctlr* ctlr)
110
{
111
	trace("%s->clock->ch9294load\n", ctlr->name);
112
 
113
	setcrt42(vga, ctlr, vga->i[0]);
114
}
115
 
116
static void
117
tvp3025load(Vga* vga, Ctlr* ctlr)
118
{
119
	uchar crt5c, x;
120
 
121
	trace("%s->clock->tvp3025load\n", ctlr->name);
122
 
123
	/*
124
	 * Crt5C bit 5 is RS4.
125
	 * Clear it to select TVP3025 registers for
126
	 * the calls to tvp302xo().
127
	 */
128
	crt5c = vgaxi(Crtx, 0x5C);
129
	vgaxo(Crtx, 0x5C, crt5c & ~0x20);
130
 
131
	tvp3020xo(0x2C, 0x00);
132
	tvp3020xo(0x2D, vga->d[0]);
133
	tvp3020xo(0x2D, vga->n[0]);
134
	tvp3020xo(0x2D, 0x08|vga->p[0]);
135
 
136
	tvp3020xo(0x2F, 0x01);
137
	tvp3020xo(0x2F, 0x01);
138
	tvp3020xo(0x2F, vga->p[0]);
139
	x = 0x54;
140
	if(vga->ctlr && (vga->ctlr->flag & Uenhanced))
141
		x = 0xC4;
142
	tvp3020xo(0x1E, x);
143
 
144
	vgaxo(Crtx, 0x5C, crt5c);
145
	vgao(MiscW, vga->misc);
146
 
147
	ctlr->flag |= Fload;
148
}
149
 
150
static void
151
tvp3026load(Vga* vga, Ctlr* ctlr)
152
{
153
	trace("%s->clock->tvp3026load\n", ctlr->name);
154
 
155
	if((vga->misc & 0x0C) != 0x0C && vga->mode->z == 1){
156
		tvp3026xo(0x1A, 0x07);
157
		tvp3026xo(0x18, 0x80);
158
		tvp3026xo(0x19, 0x98);
159
		tvp3026xo(0x2C, 0x2A);
160
		tvp3026xo(0x2F, 0x00);
161
		tvp3026xo(0x2D, 0x00);
162
		tvp3026xo(0x39, 0x18);
163
		setcrt42(vga, ctlr, 0);
164
	}
165
	else if(vga->mode->z == 8){
166
		tvp3026xo(0x1A, 0x05);
167
		tvp3026xo(0x18, 0x80);
168
		tvp3026xo(0x19, 0x4C);
169
		tvp3026xo(0x2C, 0x2A);
170
		tvp3026xo(0x2F, 0x00);
171
		tvp3026xo(0x2D, 0x00);
172
 
173
		tvp3026xo(0x2C, 0x00);
174
		tvp3026xo(0x2D, 0xC0|vga->n[0]);
175
		tvp3026xo(0x2D, vga->m[0] & 0x3F);
176
		tvp3026xo(0x2D, 0xB0|vga->p[0]);
177
		while(!(tvp3026xi(0x2D) & 0x40))
178
			;
179
 
180
		tvp3026xo(0x39, 0x38|vga->q[1]);
181
		tvp3026xo(0x2C, 0x00);
182
		tvp3026xo(0x2F, 0xC0|vga->n[1]);
183
		tvp3026xo(0x2F, vga->m[1]);
184
		tvp3026xo(0x2F, 0xF0|vga->p[1]);
185
		while(!(tvp3026xi(0x2F) & 0x40))
186
			;
187
 
188
		setcrt42(vga, ctlr, 3);
189
	}
190
 
191
	ctlr->flag |= Fload;
192
}
193
 
194
static struct {
195
	char*	name;
196
	void	(*load)(Vga*, Ctlr*);
197
} clocks[] = {
198
	{ "icd2061a",		icd2061aload, },
199
	{ "ch9294",		ch9294load, },
200
	{ "tvp3025clock",	tvp3025load, },
201
	{ "tvp3026clock",	tvp3026load, },
202
	{ 0 },
203
};
204
 
205
static void
206
init(Vga* vga, Ctlr* ctlr)
207
{
208
	char name[Namelen+1], *p;
209
	int i;
210
 
211
	if(vga->clock == 0)
212
		return;
213
 
214
	/*
215
	 * Check we know about it.
216
	 */
217
	strncpy(name, vga->clock->name, Namelen);
218
	name[Namelen] = 0;
219
	if(p = strchr(name, '-'))
220
		*p = 0;
221
	for(i = 0; clocks[i].name; i++){
222
		if(strcmp(clocks[i].name, name) == 0)
223
			break;
224
	}
225
	if(clocks[i].name == 0)
226
		error("%s: unknown clock \"%s\"\n", ctlr->name, vga->clock->name);
227
 
228
	if(vga->clock->init && (vga->clock->flag & Finit) == 0)
229
		(*vga->clock->init)(vga, vga->clock);
230
 
231
	/*
232
	 * If we don't already have a desired pclk,
233
	 * take it from the mode.
234
	 */
235
	if(vga->f[0] == 0)
236
		vga->f[0] = vga->mode->frequency;
237
	if(vga->f[0] != VgaFreq0 && vga->f[0] != VgaFreq1)
238
		vga->misc |= 0x0C;
239
 
240
	ctlr->flag |= Finit;
241
}
242
 
243
static void
244
load(Vga* vga, Ctlr* ctlr)
245
{
246
	char name[Namelen+1], *p;
247
	int i;
248
 
249
	if(vga->clock == 0 || (vga->clock->flag & Fload))
250
		return;
251
 
252
	strncpy(name, vga->clock->name, Namelen);
253
	name[Namelen] = 0;
254
	if(p = strchr(name, '-'))
255
		*p = 0;
256
 
257
	for(i = 0; clocks[i].name; i++){
258
		if(strcmp(clocks[i].name, name))
259
			continue;
260
		clocks[i].load(vga, ctlr);
261
		if(strcmp(clocks[i].name, "icd2061a") == 0){
262
			clocks[i].load(vga, ctlr);
263
			clocks[i].load(vga, ctlr);
264
		}
265
 
266
		ctlr->flag |= Fload;
267
		return;
268
	}
269
}
270
 
271
Ctlr s3clock = {
272
	"s3clock",			/* name */
273
	0,				/* snarf */
274
	0,				/* options */
275
	init,				/* init */
276
	load,				/* load */
277
	0,				/* dump */
278
};