1 #include <u.h> 2 #include <libc.h> 3 4 #include "vga.h" 5 6 static void 7 setcrt42(Vga *vga, Ctlr *ctlr, uchar index) 8 { 9 verbose("%s->clock->setcrt42\n", ctlr->name); 10 11 vgao(MiscW, vga->misc & ~0x0C); 12 outportb(Crtx+1, 0x00); 13 14 vga->crt[0x42] = (vga->crt[0x42] & 0xF0)|index; 15 vgao(MiscW, vga->misc); 16 vgaxo(Crtx, 0x42, vga->crt[0x42]); 17 } 18 19 static void 20 icd2061aload(Vga *vga, Ctlr *ctlr) 21 { 22 ulong sdata; 23 int i; 24 uchar crt42; 25 26 verbose("%s->clock->icd2061aload\n", ctlr->name); 27 /* 28 * The serial word to be loaded into the icd2061a is 29 * (2<<21)|(vga->i<<17)|((vga->n)<<10)|(vga->p<<7)|vga->d 30 * Always select ICD2061A REG2. 31 */ 32 sdata = (2<<21)|(vga->i<<17)|((vga->n)<<10)|(vga->p<<7)|vga->d; 33 34 /* 35 * The display should be already off to enable us to clock the 36 * serial data word into either MiscW or Crt42. 37 * 38 * Set the Misc register to make clock-select-out the contents of 39 * register Crt42. Must turn the sequencer off when changing bits 40 * <3:2> of Misc. Also, must set Crt42 to 0 before setting <3:2> 41 * of Misc due to a hardware glitch. 42 */ 43 vgao(MiscW, vga->misc & ~0x0C); 44 crt42 = vgaxi(Crtx, 0x42) & 0xF0; 45 outportb(Crtx+1, 0x00); 46 47 vgaxo(Seqx, 0x00, 0x00); 48 vgao(MiscW, vga->misc|0x0C); 49 vgaxo(Seqx, 0x00, 0x03); 50 51 /* 52 * Unlock the ICD2061A. The unlock sequence is at least 5 low-to-high 53 * transitions of CLK with DATA high, followed by a single low-to-high 54 * transition of CLK with DATA low. 55 * Using Crt42, CLK is bit0, DATA is bit 1. If we used MiscW, they'd 56 * be bits 2 and 3 respectively. 57 */ 58 outportb(Crtx+1, crt42|0x00); /* -DATA|-CLK */ 59 outportb(Crtx+1, crt42|0x02); /* +DATA|-CLK */ 60 for(i = 0; i < 5; i++){ 61 outportb(Crtx+1, crt42|0x03); /* +DATA|+CLK */ 62 outportb(Crtx+1, crt42|0x02); /* +DATA|-CLK */ 63 } 64 outportb(Crtx+1, crt42|0x00); /* -DATA|-CLK */ 65 outportb(Crtx+1, crt42|0x01); /* -DATA|+CLK */ 66 67 /* 68 * Now write the serial data word, framed by a start-bit and a stop-bit. 69 * The data is written using a modified Manchester encoding such that a 70 * data-bit is sampled on the rising edge of CLK and the complement of 71 * the data-bit is sampled on the previous falling edge of CLK. 72 */ 73 outportb(Crtx+1, crt42|0x00); /* -DATA|-CLK (start-bit) */ 74 outportb(Crtx+1, crt42|0x01); /* -DATA|+CLK */ 75 76 for(i = 0; i < 24; i++){ /* serial data word */ 77 if(sdata & 0x01){ 78 outportb(Crtx+1, crt42|0x01); /* -DATA|+CLK */ 79 outportb(Crtx+1, crt42|0x00); /* -DATA|-CLK (falling edge) */ 80 outportb(Crtx+1, crt42|0x02); /* +DATA|-CLK */ 81 outportb(Crtx+1, crt42|0x03); /* +DATA|+CLK (rising edge) */ 82 } 83 else { 84 outportb(Crtx+1, crt42|0x03); /* +DATA|+CLK */ 85 outportb(Crtx+1, crt42|0x02); /* +DATA|-CLK (falling edge) */ 86 outportb(Crtx+1, crt42|0x00); /* -DATA|-CLK */ 87 outportb(Crtx+1, crt42|0x01); /* -DATA|+CLK (rising edge) */ 88 } 89 sdata >>= 1; 90 } 91 92 outportb(Crtx+1, crt42|0x03); /* +DATA|+CLK (stop-bit) */ 93 outportb(Crtx+1, crt42|0x02); /* +DATA|-CLK */ 94 outportb(Crtx+1, crt42|0x03); /* +DATA|+CLK */ 95 96 /* 97 * We always use REG2 in the ICD2061A. 98 */ 99 setcrt42(vga, ctlr, 0x02); 100 } 101 102 static void 103 ch9294load(Vga *vga, Ctlr *ctlr) 104 { 105 verbose("%s->clock->ch9294load\n", ctlr->name); 106 107 setcrt42(vga, ctlr, vga->i); 108 } 109 110 static struct { 111 char* name; 112 void (*load)(Vga*, Ctlr*); 113 } clocks[] = { 114 { "icd2061a", icd2061aload, }, 115 { "ch9294", ch9294load, }, 116 { 0 }, 117 }; 118 119 static void 120 init(Vga *vga, Ctlr *ctlr) 121 { 122 char name[NAMELEN+1], *p; 123 int i; 124 125 verbose("%s->init\n", ctlr->name); 126 127 if(vga->clock == 0) 128 return; 129 130 /* 131 * Check we know about it. 132 */ 133 strncpy(name, vga->clock->name, NAMELEN); 134 name[NAMELEN] = 0; 135 if(p = strchr(name, '-')) 136 *p = 0; 137 for(i = 0; clocks[i].name; i++){ 138 if(strcmp(clocks[i].name, name) == 0) 139 break; 140 } 141 if(clocks[i].name == 0) 142 error("don't recognise s3clock \"%s\"\n", vga->clock->name); 143 144 if(vga->clock->init && (vga->clock->flag & Finit) == 0){ 145 (*vga->clock->init)(vga, vga->clock); 146 (*vga->clock->init)(vga, vga->clock); 147 (*vga->clock->init)(vga, vga->clock); 148 } 149 150 /* 151 * If we don't already have a desired pclk, 152 * take it from the mode. 153 */ 154 if(vga->f == 0) 155 vga->f = vga->mode->frequency; 156 if(vga->f != VgaFreq0 && vga->f != VgaFreq1) 157 vga->misc |= 0x0C; 158 159 ctlr->flag |= Finit; 160 } 161 162 static void 163 load(Vga *vga, Ctlr *ctlr) 164 { 165 char name[NAMELEN+1], *p; 166 int i; 167 168 verbose("%s->load\n", ctlr->name); 169 170 if(vga->clock == 0 || (vga->clock->flag & Fload)) 171 return; 172 173 strncpy(name, vga->clock->name, NAMELEN); 174 name[NAMELEN] = 0; 175 if(p = strchr(name, '-')) 176 *p = 0; 177 178 for(i = 0; clocks[i].name; i++){ 179 if(strcmp(clocks[i].name, name)) 180 continue; 181 (*clocks[i].load)(vga, ctlr); 182 183 ctlr->flag |= Fload; 184 return; 185 } 186 } 187 188 Ctlr s3clock = { 189 "s3clock", /* name */ 190 0, /* snarf */ 191 0, /* options */ 192 init, /* init */ 193 load, /* load */ 194 0, /* dump */ 195 }; 196