123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449 |
- #include <u.h>
- #include <libc.h>
- #include <bio.h>
- #include "pci.h"
- #include "vga.h"
- /*
- * Chips and Technologies HiQVideo.
- * Extensions in the 69000 over the 65550 are not fully taken into account.
- * Depths other than 8 are too slow.
- */
- enum {
- Frx = 0x3D0, /* Flat Panel Extensions Index */
- Mrx = 0x3D2, /* Multimedia Extensions Index */
- Xrx = 0x3D6, /* Configuration Extensions Index */
- };
- typedef struct {
- Pcidev* pci;
- uchar fr[256];
- uchar mr[256];
- uchar xr[256];
- } HiQVideo;
- static uchar
- hiqvideoxi(long port, uchar index)
- {
- uchar data;
- outportb(port, index);
- data = inportb(port+1);
- return data;
- }
- static void
- hiqvideoxo(long port, uchar index, uchar data)
- {
- outportb(port, index);
- outportb(port+1, data);
- }
- static void
- snarf(Vga* vga, Ctlr* ctlr)
- {
- int i;
- Pcidev *p;
- HiQVideo *hqv;
- if(vga->private == nil){
- vga->private = alloc(sizeof(HiQVideo));
- hqv = vga->private;
- if((p = pcimatch(nil, 0x102C, 0)) == nil)
- error("%s: not found\n", ctlr->name);
- switch(p->did){
- case 0x00C0: /* 69000 HiQVideo */
- vga->f[1] = 135000000;
- vga->vmz = 2048*1024;
- break;
- case 0x00E0: /* 65550 HiQV32 */
- case 0x00E4: /* 65554 HiQV32 */
- case 0x00E5: /* 65555 HiQV32 */
- vga->f[1] = 90000000;
- vga->vmz = 2048*1024;
- break;
- default:
- error("%s: DID %4.4uX unsupported\n",
- ctlr->name, p->did);
- }
- hqv->pci = p;
- }
- hqv = vga->private;
- for(i = 0; i < 0x50; i++)
- hqv->fr[i] = hiqvideoxi(Frx, i);
- for(i = 0; i < 0x60; i++)
- hqv->mr[i] = hiqvideoxi(Mrx, i);
- for(i = 0x30; i < 0x80; i++)
- vga->crt[i] = vgaxi(Crtx, i);
- for(i = 0; i < 0x100; i++)
- hqv->xr[i] = hiqvideoxi(Xrx, i);
- switch(hqv->pci->did){
- case 0x00C0: /* 69000 HiQVideo */
- vga->f[1] = 135000000;
- vga->vmz = 2048*1024;
- break;
- case 0x00E0: /* 65550 HiQV32 */
- case 0x00E4: /* 65554 HiQV32 */
- case 0x00E5: /* 65555 HiQV32 */
- /*
- * Check VCC to determine max clock.
- * 5V allows a higher rate.
- */
- if(hqv->fr[0x0A] & 0x02)
- vga->f[1] = 110000000;
- else
- vga->f[1] = 80000000;
- switch((hqv->xr[0x43]>>1) & 0x03){
- case 0:
- vga->vmz = 1*1024*1024;
- break;
- case 1:
- vga->vmz = 2*1024*1024;
- break;
- default:
- vga->vmz = 16*1024*1024;
- break;
- }
- break;
- }
- ctlr->flag |= Fsnarf;
- }
- static void
- options(Vga*, Ctlr* ctlr)
- {
- ctlr->flag |= Hlinear|Foptions;
- }
- static void
- clock(Vga* vga, Ctlr* ctlr)
- {
- double f, fmin, fvco, m;
- ulong n, nmin, nmax, pd, rd;
- /*
- * Constraints:
- * 1. 1MHz <= Fref <= 60MHz
- * 2. 150KHz <= Fref/(RD*N) <= 2MHz
- * 3. 48MHz < Fvco <= 220MHz
- * 4. 3 <= M <= 1023
- * 5. 3 <= N <= 1023
- */
- f = vga->f[0];
- /*
- * Although pd = 0 is valid, things seems more stable
- * starting at 1.
- */
- for(pd = 1; pd < 6; pd++){
- f = vga->f[0]*(1<<pd);
- if(f > 48000000 && f <= 220000000)
- break;
- }
- if(pd >= 6)
- error("%s: dclk %lud out of range\n", ctlr->name, vga->f[0]);
- vga->p[0] = pd;
- /*
- * The reference divisor has only two possible values, 1 and 4.
- */
- fmin = f;
- for(rd = 1; rd <= 4; rd += 3){
- /*
- * Find the range for n (constraint 2).
- */
- for(nmin = 3; nmin <= 1023; nmin++){
- if(RefFreq/(rd*nmin) <= 2000000)
- break;
- }
- for(nmax = 1023; nmax >= 3; nmax--){
- if(RefFreq/(rd*nmax) >= 150000)
- break;
- }
- /*
- * Now find the closest match for M and N.
- */
- for(n = nmin; n < nmax; n++){
- for(m = 3; m <= vga->m[1]; m++){
- fvco = (RefFreq*4*m)/(rd*n);
- if(fvco < 48000000 || fvco > 220000000)
- continue;
- fvco -= f;
- if(fvco < 0)
- fvco = -fvco;
- if(fvco < fmin){
- fmin = fvco;
- vga->m[0] = m;
- vga->n[0] = n;
- vga->p[0] = pd;
- vga->r[0] = rd;
- }
- }
- }
- }
- }
- static void
- init(Vga* vga, Ctlr* ctlr)
- {
- HiQVideo *hqv;
- hqv = vga->private;
- if(vga->f[0] == 0)
- vga->f[0] = vga->mode->frequency;
- vga->misc &= ~0x0C;
- hqv->fr[0x03] &= ~0x0C;
- switch(vga->mode->z){
- case 8:
- case 16:
- case 32:
- break;
- default:
- error("depth %d not supported\n", vga->mode->z);
- }
- /*
- * FR[0x01] == 1 for CRT, 2 for LCD.
- * Don't programme the clock if it's an LCD.
- */
- if((hqv->fr[0x01] & 0x03) == 0x02){
- vga->misc |= 0x08;
- hqv->fr[0x03] |= 0x08;
- }
- else{
- /*
- * Clock bits. If the desired video clock is
- * one of the two standard VGA clocks it can just be
- * set using bits <3:2> of vga->misc or Fr03,
- * otherwise the DCLK PLL needs to be programmed.
- */
- if(vga->f[0] == VgaFreq0){
- /* nothing to do */;
- }
- else if(vga->f[0] == VgaFreq1){
- vga->misc |= 0x04;
- hqv->fr[0x03] |= 0x04;
- }
- else{
- if(vga->f[0] > vga->f[1])
- error("%s: invalid dclk - %lud\n",
- ctlr->name, vga->f[0]);
-
- if((hqv->fr[0x01] & 0x03) != 0x02){
- vga->m[1] = 1023;
- clock(vga, ctlr);
- hqv->xr[0xC8] = (vga->m[0]-2) & 0xFF;
- hqv->xr[0xCA] = ((vga->m[0]-2) & 0x300)>>8;
- hqv->xr[0xC9] = (vga->n[0]-2) & 0xFF;
- hqv->xr[0xCA] |= ((vga->n[0]-2) & 0x300)>>4;
- hqv->xr[0xCB] = (vga->p[0]<<4)|(vga->r[0] == 1);
- }
- vga->misc |= 0x08;
- hqv->fr[0x03] |= 0x08;
- }
- }
- if(vga->mode->y >= 480)
- vga->misc &= ~0xC0;
- /*
- * 10 bits should be enough, but set the extended mode anyway.
- */
- hqv->xr[0x09] |= 0x01;
- vga->crt[0x30] = ((vga->mode->vt-2)>>8) & 0x0F;
- vga->crt[0x31] = ((vga->mode->y-1)>>8) & 0x0F;
- vga->crt[0x32] = (vga->mode->vrs>>8) & 0x0F;
- vga->crt[0x33] = (vga->mode->vrs>>8) & 0x0F;
- vga->crt[0x38] = (((vga->mode->ht>>3)-5)>>8) & 0x01;
- vga->crt[0x3C] = (vga->mode->ehb>>3) & 0xC0;
- vga->crt[0x41] = (vga->crt[0x13]>>8) & 0x0F;
- vga->crt[0x40] = 0x80;
- hqv->xr[0x40] |= 0x03;
- hqv->xr[0x80] |= 0x10;
- hqv->xr[0x81] &= ~0x0F;
- switch(vga->mode->z){
- case 8:
- hqv->xr[0x81] |= 0x12;
- break;
- case 16:
- hqv->xr[0x81] |= 0x15;
- break;
- case 32:
- hqv->xr[0x81] |= 0x16;
- break;
- }
- hqv->xr[0x0A] = 0x01;
- if(vga->linear && (ctlr->flag & Hlinear))
- ctlr->flag |= Ulinear;
- vga->attribute[0x11] = 0;
- ctlr->flag |= Finit;
- }
- static void
- load(Vga* vga, Ctlr* ctlr)
- {
- HiQVideo *hqv;
- hqv = vga->private;
- hiqvideoxo(Xrx, 0x0E, 0x00);
- while((vgai(Status1) & 0x08) == 0x08)
- ;
- while((vgai(Status1) & 0x08) == 0)
- ;
- vgaxo(Seqx, 0x07, 0x00);
- /*
- * Set the clock if necessary.
- */
- if((vga->misc & 0x0C) == 0x08 && (hqv->fr[0x01] & 0x03) != 0x02){
- vgao(MiscW, vga->misc & ~0x0C);
- hiqvideoxo(Frx, 0x03, hqv->fr[0x03] & ~0x0C);
- hiqvideoxo(Xrx, 0xC8, hqv->xr[0xC8]);
- hiqvideoxo(Xrx, 0xC9, hqv->xr[0xC9]);
- hiqvideoxo(Xrx, 0xCA, hqv->xr[0xCA]);
- hiqvideoxo(Xrx, 0xCB, hqv->xr[0xCB]);
- }
- hiqvideoxo(Frx, 0x03, hqv->fr[0x03]);
- vgao(MiscW, vga->misc);
- hiqvideoxo(Xrx, 0x09, hqv->xr[0x09]);
- vgaxo(Crtx, 0x30, vga->crt[0x30]);
- vgaxo(Crtx, 0x31, vga->crt[0x31]);
- vgaxo(Crtx, 0x32, vga->crt[0x32]);
- vgaxo(Crtx, 0x33, vga->crt[0x33]);
- vgaxo(Crtx, 0x38, vga->crt[0x38]);
- vgaxo(Crtx, 0x3C, vga->crt[0x3C]);
- vgaxo(Crtx, 0x41, vga->crt[0x41]);
- vgaxo(Crtx, 0x40, vga->crt[0x40]);
- hiqvideoxo(Xrx, 0x40, hqv->xr[0x40]);
- hiqvideoxo(Xrx, 0x80, hqv->xr[0x80]);
- hiqvideoxo(Xrx, 0x81, hqv->xr[0x81]);
- if(ctlr->flag & Ulinear){
- hqv->xr[0x05] = vga->vmb>>16;
- hqv->xr[0x06] = vga->vmb>>24;
- hiqvideoxo(Xrx, 0x05, hqv->xr[0x05]);
- hiqvideoxo(Xrx, 0x06, hqv->xr[0x06]);
- hqv->xr[0x0A] = 0x02;
- }
- hiqvideoxo(Xrx, 0x0A, hqv->xr[0x0A]);
- ctlr->flag |= Fload;
- }
- static ulong
- dumpmclk(uchar data[4])
- {
- double f, m, n;
- int pds, rds;
- m = data[0] & 0x7F;
- n = data[1] & 0x7F;
- pds = 1<<((data[2] & 0x70)>>4);
- if(data[2] & 0x01)
- rds = 1;
- else
- rds = 4;
- f = (RefFreq*4*(m+2))/(rds*(n+2));
- f /= pds;
- return f;
- }
- static ulong
- dumpvclk(uchar data[4])
- {
- double f, m, n;
- int pds, rds;
- m = ((data[2] & 0x03)<<8)|data[0];
- n = (((data[2] & 0x30)>>4)<<8)|data[1];
- pds = 1<<((data[3] & 0x70)>>4);
- if(data[3] & 0x01)
- rds = 1;
- else
- rds = 4;
- f = (RefFreq*4*(m+2))/(rds*(n+2));
- f /= pds;
- return f;
- }
- static void
- dump(Vga* vga, Ctlr* ctlr)
- {
- int i;
- char *name;
- HiQVideo *hqv;
- name = ctlr->name;
- hqv = vga->private;
- printitem(name, "Fr00");
- for(i = 0; i < 0x50; i++)
- printreg(hqv->fr[i]);
- printitem(name, "Mr00");
- for(i = 0; i < 0x60; i++)
- printreg(hqv->mr[i]);
- printitem(name, "Crt30");
- for(i = 0x30; i < 0x80; i++)
- printreg(vga->crt[i]);
- printitem(name, "Xr00");
- for(i = 0; i < 0x100; i++)
- printreg(hqv->xr[i]);
- printitem(ctlr->name, "CLK0");
- for(i = 0; i < 4; i++)
- printreg(hqv->xr[0xC0+i]);
- Bprint(&stdout, "%23ld", dumpvclk(&hqv->xr[0xC0]));
- printitem(ctlr->name, "CLK1");
- for(i = 0; i < 4; i++)
- printreg(hqv->xr[0xC4+i]);
- Bprint(&stdout, "%23ld", dumpvclk(&hqv->xr[0xC4]));
- printitem(ctlr->name, "CLK2");
- for(i = 0; i < 4; i++)
- printreg(hqv->xr[0xC8+i]);
- Bprint(&stdout, "%23ld", dumpvclk(&hqv->xr[0xC8]));
- printitem(ctlr->name, "MCLK");
- for(i = 0; i < 4; i++)
- printreg(hqv->xr[0xCC+i]);
- Bprint(&stdout, "%23ld", dumpmclk(&hqv->xr[0xCC]));
- printitem(ctlr->name, "m n pd rd");
- Bprint(&stdout, "%9ld %8ld - %8ld %8ld\n",
- vga->m[0], vga->n[0], vga->p[0], vga->r[0]);
- }
- Ctlr hiqvideo = {
- "hiqvideo", /* name */
- snarf, /* snarf */
- options, /* options */
- init, /* init */
- load, /* load */
- dump, /* dump */
- };
- Ctlr hiqvideohwgc = {
- "hiqvideohwgc", /* name */
- 0, /* snarf */
- 0, /* options */
- 0, /* init */
- 0, /* load */
- 0, /* dump */
- };
|