]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/aux/vga/s3clock.c
Import sources from 2011-03-30 iso image - lib
[plan9front.git] / sys / src / cmd / aux / vga / s3clock.c
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 };