17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <bio.h>
47dd7cddfSDavid du Colombier
5*9a747e4fSDavid du Colombier #include "pci.h"
67dd7cddfSDavid du Colombier #include "vga.h"
77dd7cddfSDavid du Colombier
87dd7cddfSDavid du Colombier #define SCALE(f) ((f)/10) /* could be /10 */
97dd7cddfSDavid du Colombier
107dd7cddfSDavid du Colombier static void
init(Vga * vga,Ctlr * ctlr)117dd7cddfSDavid du Colombier init(Vga* vga, Ctlr* ctlr)
127dd7cddfSDavid du Colombier {
137dd7cddfSDavid du Colombier int f, k;
147dd7cddfSDavid du Colombier ulong fmin, fvco, m, n, p, q;
157dd7cddfSDavid du Colombier double z;
167dd7cddfSDavid du Colombier
177dd7cddfSDavid du Colombier if(ctlr->flag & Finit)
187dd7cddfSDavid du Colombier return;
197dd7cddfSDavid du Colombier
207dd7cddfSDavid du Colombier if(vga->f[0] == 0)
217dd7cddfSDavid du Colombier vga->f[0] = vga->mode->frequency;
227dd7cddfSDavid du Colombier vga->misc &= ~0x0C;
23*9a747e4fSDavid du Colombier if(vga->f[0] == VgaFreq0){
24*9a747e4fSDavid du Colombier /* nothing to do */;
25*9a747e4fSDavid du Colombier }
267dd7cddfSDavid du Colombier else if(vga->f[0] == VgaFreq1)
277dd7cddfSDavid du Colombier vga->misc |= 0x04;
287dd7cddfSDavid du Colombier else
297dd7cddfSDavid du Colombier vga->misc |= 0x0C;
307dd7cddfSDavid du Colombier
317dd7cddfSDavid du Colombier /*
327dd7cddfSDavid du Colombier * Look for values of n, d and p that give
337dd7cddfSDavid du Colombier * the least error for
347dd7cddfSDavid du Colombier * Fvco = 8*RefFreq*(65-m)/(65-n)
357dd7cddfSDavid du Colombier * Fpll = Fvco/2**p
367dd7cddfSDavid du Colombier * N and m are 6 bits, p is 2 bits. Constraints:
377dd7cddfSDavid du Colombier * 110MHz <= Fvco <= 250MHz
387dd7cddfSDavid du Colombier * 40 <= n <= 62
397dd7cddfSDavid du Colombier * 1 <= m <= 62
407dd7cddfSDavid du Colombier * 0 <= p <= 3
417dd7cddfSDavid du Colombier * Should try to minimise n, m.
427dd7cddfSDavid du Colombier *
437dd7cddfSDavid du Colombier * There's nothing like brute force and ignorance.
447dd7cddfSDavid du Colombier */
457dd7cddfSDavid du Colombier fmin = vga->f[0];
467dd7cddfSDavid du Colombier vga->m[0] = 0x15;
477dd7cddfSDavid du Colombier vga->n[0] = 0x18;
487dd7cddfSDavid du Colombier vga->p[0] = 3;
497dd7cddfSDavid du Colombier for(m = 62; m > 0; m--){
507dd7cddfSDavid du Colombier for(n = 62; n >= 40; n--){
517dd7cddfSDavid du Colombier fvco = 8*SCALE(RefFreq)*(65-m)/(65-n);
527dd7cddfSDavid du Colombier if(fvco < SCALE(110000000) || fvco > SCALE(250000000))
537dd7cddfSDavid du Colombier continue;
547dd7cddfSDavid du Colombier for(p = 0; p < 4; p++){
557dd7cddfSDavid du Colombier f = SCALE(vga->f[0]) - (fvco>>p);
567dd7cddfSDavid du Colombier if(f < 0)
577dd7cddfSDavid du Colombier f = -f;
587dd7cddfSDavid du Colombier if(f < fmin){
597dd7cddfSDavid du Colombier fmin = f;
607dd7cddfSDavid du Colombier vga->m[0] = m;
617dd7cddfSDavid du Colombier vga->n[0] = n;
627dd7cddfSDavid du Colombier vga->p[0] = p;
637dd7cddfSDavid du Colombier }
647dd7cddfSDavid du Colombier }
657dd7cddfSDavid du Colombier }
667dd7cddfSDavid du Colombier }
677dd7cddfSDavid du Colombier
687dd7cddfSDavid du Colombier /*
697dd7cddfSDavid du Colombier * Now the loop clock:
707dd7cddfSDavid du Colombier * m is fixed;
717dd7cddfSDavid du Colombier * calculate n;
727dd7cddfSDavid du Colombier * set z to the lower bound (110MHz) and calculate p and q.
737dd7cddfSDavid du Colombier */
747dd7cddfSDavid du Colombier vga->m[1] = 61;
757dd7cddfSDavid du Colombier if(ctlr->flag & Uenhanced)
767dd7cddfSDavid du Colombier k = 64/8;
777dd7cddfSDavid du Colombier else
787dd7cddfSDavid du Colombier k = 8/8;
797dd7cddfSDavid du Colombier n = 65 - 4*k;
807dd7cddfSDavid du Colombier fvco = (8*RefFreq*(65-vga->m[0]))/(65-vga->n[0]);
817dd7cddfSDavid du Colombier vga->f[1] = fvco;
827dd7cddfSDavid du Colombier z = 110.0*(65-n)/(4*(fvco/1000000.0)*k);
837dd7cddfSDavid du Colombier if(z <= 16){
847dd7cddfSDavid du Colombier for(p = 0; p < 4; p++){
857dd7cddfSDavid du Colombier if(1<<(p+1) > z)
867dd7cddfSDavid du Colombier break;
877dd7cddfSDavid du Colombier }
887dd7cddfSDavid du Colombier q = 0;
897dd7cddfSDavid du Colombier }
907dd7cddfSDavid du Colombier else{
917dd7cddfSDavid du Colombier p = 3;
927dd7cddfSDavid du Colombier q = (z - 16)/16 + 1;
937dd7cddfSDavid du Colombier }
947dd7cddfSDavid du Colombier vga->n[1] = n;
957dd7cddfSDavid du Colombier vga->p[1] = p;
967dd7cddfSDavid du Colombier vga->q[1] = q;
977dd7cddfSDavid du Colombier
987dd7cddfSDavid du Colombier ctlr->flag |= Finit;
997dd7cddfSDavid du Colombier }
1007dd7cddfSDavid du Colombier
1017dd7cddfSDavid du Colombier Ctlr tvp3026clock = {
1027dd7cddfSDavid du Colombier "tvp3026clock", /* name */
1037dd7cddfSDavid du Colombier 0, /* snarf */
1047dd7cddfSDavid du Colombier 0, /* options */
1057dd7cddfSDavid du Colombier init, /* init */
1067dd7cddfSDavid du Colombier 0, /* load */
1077dd7cddfSDavid du Colombier 0, /* dump */
1087dd7cddfSDavid du Colombier };
109