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 }; 279