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