From 150ca26a9045f63dd57e8c7f1ac4d2b66b18ee2d Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Fri, 25 Jan 2002 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 2002-01-25 --- mtx/devrtc.c | 421 ++++++++++++++++++++++ mtx/l.s | 3 + mtx/mem.h | 1 + pc/devtv.c | 854 +++++++++++++++++++++++++++++++++++++++++++++ pc/vgamga4xx.c | 559 +++++++++++++++++++++++++++++ port/devbridge.c | 4 +- port/devloopback.c | 2 +- port/devsdp.c | 4 +- 8 files changed, 1843 insertions(+), 5 deletions(-) create mode 100644 mtx/devrtc.c create mode 100644 pc/devtv.c create mode 100644 pc/vgamga4xx.c diff --git a/mtx/devrtc.c b/mtx/devrtc.c new file mode 100644 index 0000000000000000000000000000000000000000..bcc640a21afe8cf7280c04a5f014da5381e0572a --- /dev/null +++ b/mtx/devrtc.c @@ -0,0 +1,421 @@ +/* + * M48T59/559 Timekeeper + */ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "../port/error.h" + +#include "io.h" + +enum{ + STB0 = 0x74, + STB1 = 0x75, + Data = 0x77, + + NVOFF= 0, + NVLEN= 0x1ff0, /* length in bytes of NV RAM */ + + /* + * register offsets into time of day clock + */ + NVflags= 0x1ff0, + NVctl= 0x1ff8, + NVsec, + NVmin, + NVhour, + NVday, /* (1 = Sun) */ + NVmday, /* (1-31) */ + NVmon, /* (1-12) */ + NVyear, /* (0-99) */ + + /* NVctl */ + RTwrite = (1<<7), + RTread = (1<<6), + RTsign = (1<<5), + RTcal = 0x1f, + + Qdir = 0, + Qrtc, + Qnvram, +}; + +/* + * broken down time + */ +typedef struct +{ + int sec; + int min; + int hour; + int mday; + int mon; + int year; +} Rtc; + +QLock rtclock; /* mutex on nvram operations */ + +static Dirtab rtcdir[]={ + ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555, + "rtc", {Qrtc, 0}, 0, 0644, + "nvram", {Qnvram, 0}, 0, 0600, +}; + +static ulong rtc2sec(Rtc*); +static void sec2rtc(ulong, Rtc*); +static void setrtc(Rtc*); +static void nvcksum(void); +static void nvput(int, uchar); +static uchar nvget(int); + +static Chan* +rtcattach(char *spec) +{ + return devattach('r', spec); +} + +static Walkqid* +rtcwalk(Chan *c, Chan *nc, char **name, int nname) +{ + return devwalk(c, nc, name, nname, rtcdir, nelem(rtcdir), devgen); +} + +static int +rtcstat(Chan *c, uchar *dp, int n) +{ + return devstat(c, dp, n, rtcdir, nelem(rtcdir), devgen); +} + +static Chan* +rtcopen(Chan *c, int omode) +{ + omode = openmode(omode); + switch((ulong)c->qid.path){ + case Qrtc: + if(strcmp(up->user, eve)!=0 && omode!=OREAD) + error(Eperm); + break; + case Qnvram: + if(strcmp(up->user, eve)!=0 || !cpuserver) + error(Eperm); + } + return devopen(c, omode, rtcdir, nelem(rtcdir), devgen); +} + +static void +rtcclose(Chan*) +{ +} + +static long +rtcread(Chan *c, void *buf, long n, vlong off) +{ + char *p; + ulong t; + int i; + ulong offset = off; + + if(c->qid.type & QTDIR) + return devdirread(c, buf, n, rtcdir, nelem(rtcdir), devgen); + + switch((ulong)c->qid.path){ + case Qrtc: + qlock(&rtclock); + t = rtctime(); + qunlock(&rtclock); + n = readnum(offset, buf, n, t, 12); + return n; + case Qnvram: + offset += NVOFF; + if(offset > NVLEN) + return 0; + if(n > NVLEN - offset) + n = NVLEN - offset; + p = buf; + qlock(&rtclock); + for(i = 0; i < n; i++) + p[i] = nvget(i+offset); + qunlock(&rtclock); + return n; + } + error(Egreg); + return -1; /* never reached */ +} + +static long +rtcwrite(Chan *c, void *buf, long n, vlong off) +{ + Rtc rtc; + ulong secs; + char *cp, *ep; + int i; + ulong offset = off; + + switch((ulong)c->qid.path){ + case Qrtc: + if(offset!=0) + error(Ebadarg); + /* + * read the time + */ + cp = ep = buf; + ep += n; + while(cp < ep){ + if(*cp>='0' && *cp<='9') + break; + cp++; + } + secs = strtoul(cp, 0, 0); + /* + * convert to bcd + */ + sec2rtc(secs, &rtc); + /* + * write it + */ + qlock(&rtclock); + setrtc(&rtc); + qunlock(&rtclock); + return n; + case Qnvram: + offset += NVOFF; + if(offset > NVLEN) + return 0; + if(n > NVLEN - offset) + n = NVLEN - offset; + qlock(&rtclock); + for(i = 0; i < n; i++) + nvput(i+offset, ((uchar*)buf)[i]); + nvcksum(); + qunlock(&rtclock); + return n; + } + error(Egreg); + return -1; /* never reached */ +} + +long +rtcbwrite(Chan *c, Block *bp, ulong offset) +{ + return devbwrite(c, bp, offset); +} + +Dev rtcdevtab = { + 'r', + "rtc", + + devreset, + devinit, + devshutdown, + rtcattach, + rtcwalk, + rtcstat, + rtcopen, + devcreate, + rtcclose, + rtcread, + devbread, + rtcwrite, + devbwrite, + devremove, + devwstat, +}; + +static void +nvput(int offset, uchar val) +{ + outb(STB0, offset); + outb(STB1, offset>>8); + outb(Data, val); +} + +static uchar +nvget(int offset) +{ + outb(STB0, offset); + outb(STB1, offset>>8); + return inb(Data); +} + +static void +nvcksum(void) +{ +} + +static int +getbcd(int bcd) +{ + return (bcd&0x0f) + 10 * (bcd>>4); +} + +static int +putbcd(int val) +{ + return (val % 10) | (((val/10) % 10) << 4); +} + +long +rtctime(void) +{ + int ctl; + Rtc rtc; + + /* + * convert from BCD + */ + ctl = nvget(NVctl); + ctl &= RTsign|RTcal; + nvput(NVctl, ctl|RTread); + + rtc.sec = getbcd(nvget(NVsec) & 0x7f); + rtc.min = getbcd(nvget(NVmin)); + rtc.hour = getbcd(nvget(NVhour)); + rtc.mday = getbcd(nvget(NVmday)); + rtc.mon = getbcd(nvget(NVmon)); + rtc.year = getbcd(nvget(NVyear)); + if(rtc.year < 70) + rtc.year += 2000; + else + rtc.year += 1900; + + nvput(NVctl, ctl); + + return rtc2sec(&rtc); +} + +static void +setrtc(Rtc *rtc) +{ + int ctl; + + ctl = nvget(NVctl); + ctl &= RTsign|RTcal; + nvput(NVctl, ctl|RTwrite); + + nvput(NVsec, putbcd(rtc->sec)); + nvput(NVmin, putbcd(rtc->min)); + nvput(NVhour, putbcd(rtc->hour)); + nvput(NVmday, putbcd(rtc->mday)); + nvput(NVmon, putbcd(rtc->mon)); + nvput(NVyear, putbcd(rtc->year % 100)); + + nvput(NVctl, ctl); +} + +#define SEC2MIN 60L +#define SEC2HOUR (60L*SEC2MIN) +#define SEC2DAY (24L*SEC2HOUR) + +/* + * days per month plus days/year + */ +static int dmsize[] = +{ + 365, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; +static int ldmsize[] = +{ + 366, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; + +/* + * return the days/month for the given year + */ +static int * +yrsize(int y) +{ + + if((y%4) == 0 && ((y%100) != 0 || (y%400) == 0)) + return ldmsize; + else + return dmsize; +} + +/* + * compute seconds since Jan 1 1970 + */ +static ulong +rtc2sec(Rtc *rtc) +{ + ulong secs; + int i; + int *d2m; + + secs = 0; + + /* + * seconds per year + */ + for(i = 1970; i < rtc->year; i++){ + d2m = yrsize(i); + secs += d2m[0] * SEC2DAY; + } + + /* + * seconds per month + */ + d2m = yrsize(rtc->year); + for(i = 1; i < rtc->mon; i++) + secs += d2m[i] * SEC2DAY; + + secs += (rtc->mday-1) * SEC2DAY; + secs += rtc->hour * SEC2HOUR; + secs += rtc->min * SEC2MIN; + secs += rtc->sec; + + return secs; +} + +/* + * compute rtc from seconds since Jan 1 1970 + */ +static void +sec2rtc(ulong secs, Rtc *rtc) +{ + int d; + long hms, day; + int *d2m; + + /* + * break initial number into days + */ + hms = secs % SEC2DAY; + day = secs / SEC2DAY; + if(hms < 0) { + hms += SEC2DAY; + day -= 1; + } + + /* + * generate hours:minutes:seconds + */ + rtc->sec = hms % 60; + d = hms / 60; + rtc->min = d % 60; + d /= 60; + rtc->hour = d; + + /* + * year number + */ + if(day >= 0) + for(d = 1970; day >= *yrsize(d); d++) + day -= *yrsize(d); + else + for (d = 1970; day < 0; d--) + day += *yrsize(d-1); + rtc->year = d; + + /* + * generate month + */ + d2m = yrsize(rtc->year); + for(d = 1; day >= d2m[d]; d++) + day -= d2m[d]; + rtc->mday = day + 1; + rtc->mon = d; + + return; +} diff --git a/mtx/l.s b/mtx/l.s index 9415ad95594f9b8a9fb964e494083e82451e90d6..807c34de5f2c9f88d250d80ef7188c6ddc679ad9 100644 --- a/mtx/l.s +++ b/mtx/l.s @@ -288,6 +288,9 @@ tas0: TEXT firmware(SB), $0 MOVW initsprg3(SB), R3 MOVW R3, SPR(SPRG3) +// MOVW $0x4000, R3 +// MOVW R3, SPR(SPRG3) + MOVW R0, SPR(HID0) MOVW $MSR_IP, R4 MOVW R4, SPR(SRR1) MOVW $0xfff00100, R5 diff --git a/mtx/mem.h b/mtx/mem.h index 11e1771ce8ed3e17444d7c8f48777022a4219694..a4f5307bc613faf24c79c74b0ad61e116e88ebd1 100644 --- a/mtx/mem.h +++ b/mtx/mem.h @@ -99,6 +99,7 @@ #define MSR_IP BIT(25) /* Exception prefix 0x000/0xFFF */ #define MSR_IR BIT(26) /* Instruction MMU enable */ #define MSR_DR BIT(27) /* Data MMU enable */ +#define MSR_PM BIT(29) /* Performance Monitor marked mode (604e specific) */ #define MSR_RI BIT(30) /* Recoverable Exception */ #define MSR_LE BIT(31) /* Little-Endian enable */ diff --git a/pc/devtv.c b/pc/devtv.c new file mode 100644 index 0000000000000000000000000000000000000000..2d1fc4a5563f5f8e2c8146e7d5ebac276dac0c22 --- /dev/null +++ b/pc/devtv.c @@ -0,0 +1,854 @@ +/* + * Driver for Bt848 TV tuner. WARNING, I used the Linux driver as + * documentation. + * + */ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "../port/error.h" +#include "io.h" + +enum { + Qdir = 0, + Qdata, + Qctl, + Qregs, + Qdbuf, + + Brooktree_vid = 0x109e, + Brooktree_848_did = 0x0350, + Intel_vid = 0x8086, + Intel_82437_did = 0x122d, + + K = 1024, + M = K * K, + + ntsc_rawpixels = 910, + ntsc_sqpixels = 780, // Including blanking & inactive + ntsc_hactive = 640, + ntsc_vactive = 480, + ntsc_clkx1delay = 135, // Clock ticks. + ntsc_clkx1hactive = 754, + ntsc_vdelay = 26, // # of scan lines. + ntsc_vscale = 0, + + i2c_timing = 7 << 4, + i2c_bt848w3b = 1 << 2, + i2c_bt848scl = 1 << 1, + i2c_bt848sda = 1 << 0, + + i2c_miroproee = 0x80, // MIRO PRO EEPROM + i2c_tea6300 = i2c_miroproee, + i2c_tda8425 = 0x82, + i2c_tda9840 = 0x84, + i2c_tda9850 = 0xb6, + i2c_haupee = 0xa0, // Hauppage EEPROM + i2c_stbee = 0xae, // STB EEPROM + + Bt848_miropro = 0, + Bt848_miro, + + // Bit fields. + iform_muxsel1 = 3 << 5, // 004 + iform_muxsel0 = 2 << 5, + iform_xtselmask = 3 << 3, + iform_xtauto = 3 << 3, + iform_formatmask = 7 << 0, + iform_ntsc = 1 << 0, + + control_ldec = 1 << 5, // 02C + contrast_100percent = 0xd8, // 030 + + vscale_interlaced = 1 << 5, // 04C + + adelay_ntsc = 104, // 060 + bdelay_ntsc = 93, // 064 + adc_crush = 1 << 0, // 068 + + colorfmt_rgb16 = (2 << 4) | (2 << 0), // 0D4 + colorctl_gamma = 1 << 4, // 0D8 + capctl_fullframe = 1 << 4, // 0DC + capctl_captureodd = 1 << 1, + capctl_captureeven = 1 << 0, + vbipacksize = 0x190, // 0E0 + + intstat_i2crack = 1 << 25, // 100 + intstat_scerr = 1 << 19, + intstat_ocerr = 1 << 18, + intstat_fbus = 1 << 12, + intstat_risci = 1 << 11, + intstat_i2cdone = 1 << 8, + intstat_vpress = 1 << 5, + intstat_hlock = 1 << 4, + intstat_vsync = 1 << 1, + intstat_fmtchg = 1 << 0, + intmask_etbf = 1 << 23, // 104 + + gpiodmactl_pltp23_16 = 2 << 6, // 10C + gpiodmactl_pltp23_0 = 0 << 6, + gpiodmactl_pltp1_16 = 2 << 4, + gpiodmactl_pltp1_0 = 0 << 4, + gpiodmactl_pktp_32 = 3 << 2, + gpiodmactl_pktp_0 = 0 << 2, + gpiodmactl_riscenable = 1 << 1, + gpiodmactl_fifoenable = 1 << 0, + + // RISC instructions and parameters. + fifo_vre = 0x4, + fifo_vro = 0xC, + fifo_fm1 = 0x6, + + riscirq = 1 << 24, + riscwrite = 0x1 << 28, + riscwrite_sol = 1 << 27, + riscwrite_eol = 1 << 26, + riscskip = 0x2 << 28, + riscjmp = 0x7 << 28, + riscsync = 0x8 << 28, + riscsync_resync = 1 << 15, + riscsync_vre = fifo_vre << 0, + riscsync_vro = fifo_vro << 0, + riscsync_fm1 = fifo_fm1 << 0, +}; + +typedef struct { + ushort vid; + ushort did; + char *name; +} Variant; + +typedef struct { + ulong devstat; // 000 + ulong iform; // 004 + ulong tdec; // 008 + ulong ecrop; // 00C + ulong evdelaylo; // 010 + ulong evactivelo; // 014 + ulong ehdelaylo; // 018 + ulong ehactivelo; // 01C + ulong ehscalehi; // 020 + ulong ehscalelo; // 024 + ulong bright; // 028 + ulong econtrol; // 02C + ulong contrastlo; // 030 + ulong satulo; // 034 + ulong satvlo; // 038 + ulong hue; // 03C + ulong escloop; // 040 + ulong pad0; // 044 + ulong oform; // 048 + ulong evscalehi; // 04C + ulong evscalelo; // 050 + ulong test; // 054 + ulong pad1[2]; // 058-05C + ulong adelay; // 060 + ulong bdelay; // 064 + ulong adc; // 068 + ulong evtc; // 06C + ulong pad2[3]; // 070-078 + ulong sreset; // 07C + ulong tglb; // 080 + ulong tgctrl; // 084 + ulong pad3; // 088 + ulong ocrop; // 08C + ulong ovdelaylo; // 090 + ulong ovactivelo; // 094 + ulong ohdelaylo; // 098 + ulong ohactivelo; // 09C + ulong ohscalehi; // 0A0 + ulong ohscalelo; // 0A4 + ulong pad4; // 0A8 + ulong ocontrol; // 0AC + ulong pad5[4]; // 0B0-0BC + ulong oscloop; // 0C0 + ulong pad6[2]; // 0C4-0C8 + ulong ovscalehi; // 0CC + ulong ovscalelo; // 0D0 + ulong colorfmt; // 0D4 + ulong colorctl; // 0D8 + ulong capctl; // 0DC + ulong vbipacksize; // 0E0 + ulong vbipackdel; // 0E4 + ulong fcap; // 0E8 + ulong ovtc; // 0EC + ulong pllflo; // 0F0 + ulong pllfhi; // 0F4 + ulong pllxci; // 0F8 + ulong dvsif; // 0FC + ulong intstat; // 100 + ulong intmask; // 104 + ulong pad7; // 108 + ulong gpiodmactl; // 10C + ulong i2c; // 110 + ulong riscstrtadd; // 114 + ulong gpioouten; // 118 + ulong gpioreginp; // 11C + ulong risccount; // 120 + ulong pad8[55]; // 124-1FC + ulong gpiodata[64]; // 200-2FC +} Bt848; + +typedef struct { + char *name; + ushort freq_vhfh; // Start frequency + ushort freq_uhf; + uchar VHF_L; + uchar VHF_H; + uchar UHF; + uchar cfg; + ushort offs; +} Tuner; + +typedef struct { + Lock; + Bt848 *bt848; + Variant *variant; + Tuner *tuner; + Pcidev *pci; + ulong *program; // Current DMA program + uchar i2ctuneraddr; + uchar i2ccmd; // I2C command + int board; // What board is this? + + uchar *dbuf; +} Tv; + +// Tuner related. +enum { + TemicPAL = 0, + PhilipsPAL, + PhilipsNTSC, + PhilipsSECAM, + Notuner, + PhilipsPALI, + TemicNTSC, + TemicPALI, + Temic4036, + AlpsTSBH1, + AlpsTSBE1, + + Freqmultiplier = 16, +}; + +static Tuner tuners[] = { + {"Temic PAL", Freqmultiplier * 140.25, Freqmultiplier * 463.25, + 0x02, 0x04, 0x01, 0x8e, 623 }, + {"Philips PAL_I", Freqmultiplier * 140.25, Freqmultiplier * 463.25, + 0xa0, 0x90, 0x30, 0x8e, 623 }, + {"Philips NTSC", Freqmultiplier * 157.25, Freqmultiplier * 451.25, + 0xA0, 0x90, 0x30, 0x8e, 732 }, + {"Philips SECAM", Freqmultiplier * 168.25, Freqmultiplier * 447.25, + 0xA7, 0x97, 0x37, 0x8e, 623 }, + {"NoTuner", 0, 0, + 0x00, 0x00, 0x00, 0x00, 0 }, + {"Philips PAL", Freqmultiplier * 168.25, Freqmultiplier * 447.25, + 0xA0, 0x90, 0x30, 0x8e, 623 }, + {"Temic NTSC", Freqmultiplier * 157.25, Freqmultiplier * 463.25, + 0x02, 0x04, 0x01, 0x8e, 732 }, + {"TEMIC PAL_I", Freqmultiplier * 170.00, Freqmultiplier * 450.00, + 0x02, 0x04, 0x01, 0x8e, 623 }, + {"Temic 4036 FY5 NTSC", Freqmultiplier * 157.25, Freqmultiplier * 463.25, + 0xa0, 0x90, 0x30, 0x8e, 732 }, + {"Alps TSBH1", Freqmultiplier * 137.25, Freqmultiplier * 385.25, + 0x01, 0x02, 0x08, 0x8e, 732 }, + {"Alps TSBE1", Freqmultiplier * 137.25, Freqmultiplier * 385.25, + 0x01, 0x02, 0x08, 0x8e, 732 }, +}; + +enum { + CMvstart, + CMvstop, + CMchannel, +}; + +static Cmdtab tvctlmsg[] = { + CMvstart, "vstart", 3, + CMvstop, "vstop", 1, + CMchannel, "channel", 3, +}; + +static Dirtab tvtab[]={ + ".", { Qdir, 0, QTDIR }, 0, DMDIR|0555, + "tv", { Qdata, 0 }, 0, 0600, + "tvctl", { Qctl, 0 }, 0, 0600, + "tvregs", { Qregs, 0 }, 0, 0400, + "tvdbuf", { Qdbuf, 0 }, 0, 0400, +}; + +static Variant variant[] = { +{ Brooktree_vid, Brooktree_848_did, "Brooktree 848 TV tuner", }, +}; + +static char *boards[] = { + "MIRO PRO", + "MIRO", +}; + +static Tv *tv; + +static int i2cread(Tv *, uchar, uchar *); +static int i2cwrite(Tv *, uchar, uchar, uchar, int); +static void tvinterrupt(Ureg *, Tv *); +static void vstart(Tv *, ulong, int); +static void vstop(Tv *); +static void frequency(Tv *, int, int); + +static void +tvinit(void) +{ + Pcidev *pci; + ulong intmask; + + if (!getconf("tv0")) + return; + + // Test for a triton memory controller. + intmask = 0; + if (pcimatch(nil, Intel_vid, Intel_82437_did)) + intmask = intmask_etbf; + + pci = nil; + while ((pci = pcimatch(pci, 0, 0)) != nil) { + int i, t; + Bt848 *bt848; + ushort hscale, hdelay; + uchar v; + + for (i = 0; i != nelem(variant); i++) + if (pci->vid == variant[i].vid && pci->did == variant[i].did) + break; + if (i == nelem(variant)) + continue; + + if (tv) { + print("#V: Currently there is only support for one TV, ignoring %s\n", + variant[i].name); + continue; + } + + tv = (Tv *)malloc(sizeof(Tv)); + assert(tv); + + tv->variant = &variant[i]; + tv->pci = pci; + tv->bt848 = (Bt848 *)upamalloc(pci->mem[0].bar & ~0x0F, 4 * K, K); + if (tv->bt848 == nil) + panic("#V: Cannot allocate memory for Bt848\n"); + bt848 = tv->bt848; + + // i2c stuff. + if (pci->did >= 878) + tv->i2ccmd = 0x83; + else + tv->i2ccmd = i2c_timing | i2c_bt848scl | i2c_bt848sda; + + { + bt848->gpioouten = 0; + + bt848->gpioouten |= 1 << 5; + bt848->gpiodata[0] |= 1 << 5; + microdelay(2500); + bt848->gpiodata[0] |= 1 << 5; + microdelay(2500); + } + + if (i2cread(tv, i2c_haupee, &v)) + panic("#V: Cannot deal with hauppauge boards\n"); + if (i2cread(tv, i2c_stbee, &v)) + panic("#V: Cannot deal with STB cards\n"); + if (i2cread(tv, i2c_miroproee, &v)) { + tv->board = Bt848_miropro; + t = ((bt848->gpiodata[0] >> 10) - 1) & 7; + } + else { + tv->board = Bt848_miro; + t = ((bt848->gpiodata[0] >> 10) - 1) & 7; + } + + if (t >= nelem(tuners)) + t = 4; + tv->tuner = &tuners[t]; + tv->i2ctuneraddr = + i2cread(tv, 0xc1, &v)? 0xc0: + i2cread(tv, 0xc3, &v)? 0xc2: + i2cread(tv, 0xc5, &v)? 0xc4: + i2cread(tv, 0xc7, &v)? 0xc6: -1; + + bt848->capctl = capctl_fullframe; + bt848->adelay = adelay_ntsc; + bt848->bdelay = bdelay_ntsc; + bt848->iform = iform_muxsel0|iform_xtauto|iform_ntsc; + bt848->vbipacksize = vbipacksize & 0xff; + bt848->vbipackdel = (vbipacksize >> 8) & 1; + + // setpll(bt848); + + bt848->colorfmt = colorfmt_rgb16; + + hscale = (ntsc_rawpixels * 4096) / ntsc_sqpixels - 4096; + hdelay = (ntsc_clkx1delay * ntsc_hactive) / ntsc_clkx1hactive; + + bt848->ovtc = bt848->evtc = 0; + bt848->ehscalehi = bt848->ohscalehi = (hscale >> 8) & 0xff; + bt848->ehscalelo = bt848->ohscalelo = hscale & 0xff; + bt848->evscalehi &= ~0x1f; + bt848->ovscalehi &= ~0x1f; + bt848->evscalehi |= vscale_interlaced | ((ntsc_vscale >> 8) & 0x1f); + bt848->ovscalehi |= vscale_interlaced | (ntsc_vscale >> 8) & 0x1f; + bt848->evscalelo = bt848->ovscalelo = ntsc_vscale & 0xff; + bt848->ehactivelo = bt848->ohactivelo = ntsc_hactive & 0xff; + bt848->ehdelaylo = bt848->ohdelaylo = hdelay & 0xff; + bt848->evactivelo = bt848->ovactivelo = ntsc_vactive & 0xff; + bt848->evdelaylo = bt848->ovdelaylo = ntsc_vdelay & 0xff; + bt848->ecrop = bt848->ocrop = + ((ntsc_hactive >> 8) & 0x03) | + ((hdelay >> 6) & 0x0C) | + ((ntsc_vactive >> 4) & 0x30) | + ((ntsc_vdelay >> 2) & 0xC0); + + bt848->colorctl = colorctl_gamma; + bt848->capctl = 0; + bt848->gpiodmactl = gpiodmactl_pltp23_16 | + gpiodmactl_pltp1_16 | gpiodmactl_pktp_32; + bt848->gpioreginp = 0; + bt848->contrastlo = contrast_100percent; + bt848->bright = 16; + bt848->adc = (2 << 6) | adc_crush; + bt848->econtrol = bt848->ocontrol = control_ldec; + bt848->escloop = bt848->oscloop = 0; + bt848->intstat = (ulong)-1; + bt848->intmask = intmask | + intstat_vsync | intstat_scerr | intstat_risci | intstat_ocerr | + intstat_vpress | intstat_fmtchg | intstat_hlock; + + bt848->gpioouten &= ~0xF; + bt848->gpioouten |= 0xF; + bt848->gpiodata[0] &= ~0xF; + bt848->gpiodata[0] |= 2; // Enable audio on the MIRO card. + + print("#V: %s (rev %d) (%s/%s) %.8ulX, intl %d\n", + tv->variant->name, pci->rid, boards[tv->board], + tv->tuner->name, pci->mem[0].bar & ~0x0F, pci->intl); + + intrenable(pci->intl, (void (*)(Ureg *, void *))tvinterrupt, + tv, pci->tbdf, "tv"); + + tv->dbuf = (uchar *)malloc(ntsc_hactive * ntsc_vactive * sizeof(ushort)); + memset(tv->dbuf, 0, ntsc_hactive * ntsc_vactive * sizeof(ushort)); + } +} + +static Chan* +tvattach(char *spec) +{ + return devattach('V', spec); +} + +static Walkqid * +tvwalk(Chan *c, Chan *nc, char **name, int nname) +{ + return devwalk(c, nc, name, nname, tvtab, nelem(tvtab), devgen); +} + +static int +tvstat(Chan *c, uchar *db, int n) +{ + return devstat(c, db, n, tvtab, nelem(tvtab), devgen); +} + +static Chan* +tvopen(Chan *c, int omode) +{ + return devopen(c, omode, tvtab, nelem(tvtab), devgen); +} + +static void +tvclose(Chan *) +{} + +static long +tvread(Chan *c, void *a, long n, vlong offset) +{ + static char regs[10 * K]; + static int regslen; + char *e, *p; + int nbytes; + + USED(offset); + + switch((int)c->qid.path) { + case Qdir: + return devdirread(c, a, n, tvtab, nelem(tvtab), devgen); + case Qdata: + error(Eio); + case Qregs: + if (offset == 0) { + Bt848 *bt848 = tv->bt848; + int i; + + e = regs + sizeof(regs); + p = regs; + for (i = 0; i < 0x300 >> 2; i++) + p = seprint(p, e, "%.3X %.8ulX\n", i << 2, ((ulong *)bt848)[i]); + regslen = p - regs; + } + + if (offset >= regslen) + return 0; + if (offset + n > regslen) + n = regslen - offset; + + return readstr(offset, a, n, ®s[offset]); + + case Qdbuf: + if (offset > ntsc_hactive * ntsc_vactive * sizeof(ushort)) { + memset(tv->dbuf, 0xaa, + ntsc_hactive * ntsc_vactive * sizeof(ushort)); + return 0; + } + + if (offset + n > ntsc_hactive * ntsc_vactive * sizeof(ushort)) + nbytes = ntsc_hactive * ntsc_vactive * sizeof(ushort) - offset; + else + nbytes = n; + memmove(a, tv->dbuf + offset, nbytes); + return nbytes; + + default: + n=0; + break; + } + return n; +} + +static long +tvwrite(Chan *c, void *a, long n, vlong) +{ + Cmdbuf *cb; + Cmdtab *ct; + + switch((int)c->qid.path) { + case Qctl: + cb = parsecmd(a, n); + if(waserror()){ + free(cb); + nexterror(); + } + ct = lookupcmd(cb, tvctlmsg, nelem(tvctlmsg)); + switch (ct->index) { + case CMvstart: + vstart(tv, strtoul(cb->f[1], (char **)nil, 0), + (int)strtoul(cb->f[2], (char **)nil, 0)); + break; + case CMvstop: + vstop(tv); + break; + case CMchannel: + frequency(tv, (int)strtol(cb->f[1], (char **)nil, 0), + (int)strtol(cb->f[2], (char **)nil, 0)); + break; + } + poperror(); + break; + + default: + error(Eio); + } + return n; +} + +Dev tvdevtab = { + 'V', + "tv", + + devreset, + tvinit, + devshutdown, + tvattach, + tvwalk, + tvstat, + tvopen, + devcreate, + tvclose, + tvread, + devbread, + tvwrite, + devbwrite, + devremove, + devwstat, +}; + +static void +tvinterrupt(Ureg *, Tv *tv) +{ + Bt848 *bt848 = tv->bt848; + ulong status; + + while ((status = bt848->intstat & bt848->intmask) != 0) { + bt848->intstat = status; + + if ((status & intstat_fmtchg) == intstat_fmtchg) { + iprint("int: fmtchg\n"); + status &= ~intstat_fmtchg; + } + + if ((status & intstat_vpress) == intstat_vpress) { + iprint("int: vpress\n"); + status &= ~intstat_vpress; + } + + if ((status & intstat_vsync) == intstat_vsync) + status &= ~intstat_vsync; + + if ((status & intstat_scerr) == intstat_scerr) { + iprint("int: scerr\n"); + bt848->gpiodmactl &= + ~(gpiodmactl_riscenable|gpiodmactl_fifoenable); + bt848->gpiodmactl |= gpiodmactl_fifoenable; + bt848->gpiodmactl |= gpiodmactl_riscenable; + status &= ~intstat_scerr; + } + + if ((status & intstat_risci) == intstat_risci) { + iprint("int: risci\n"); + status &= ~intstat_risci; + } + + if ((status & intstat_ocerr) == intstat_ocerr) { + iprint("int: ocerr\n"); + status &= ~intstat_ocerr; + } + + if ((status & intstat_fbus) == intstat_fbus) { + iprint("int: fbus\n"); + status &= ~intstat_fbus; + } + + if (status) + iprint("int: ignored interrupts %.8ulX\n", status); + } +} + +static int +i2cread(Tv *tv, uchar off, uchar *v) +{ + Bt848 *bt848 = tv->bt848; + ulong intstat; + int i; + + bt848->intstat = intstat_i2cdone; + bt848->i2c = (off << 24) | tv->i2ccmd; + + intstat = -1; + for (i = 0; i != 1000; i++) { + if ((intstat = bt848->intstat) & intstat_i2cdone) + break; + microdelay(1000); + } + + if (i == 1000) { + print("i2cread: timeout\n"); + return 0; + } + + if ((intstat & intstat_i2crack) == 0) + return 0; + + *v = bt848->i2c >> 8; + return 1; +} + +static int +i2cwrite(Tv *tv, uchar off, uchar d1, uchar d2, int both) +{ + Bt848 *bt848 = tv->bt848; + ulong intstat, data; + int i; + + bt848->intstat = intstat_i2cdone; + data = (off << 24) | (d1 << 16) | tv->i2ccmd; + if (both) + data |= (d2 << 8) | i2c_bt848w3b; + bt848->i2c = data; + + intstat = 0; + for (i = 0; i != 1000; i++) { + if ((intstat = bt848->intstat) & intstat_i2cdone) + break; + microdelay(1000); + } + + if (i == 1000) { + print("i2cread: timeout\n"); + return 0; + } + + if ((intstat & intstat_i2crack) == 0) + return 0; + + return 1; +} + + +static ulong * +riscprogram(ulong paddr, int stride, int bpp) +{ + ulong *p, *pbase; + int i; + + pbase = p = (ulong *)malloc((ntsc_vactive + 5) * 2 * sizeof(ulong)); + assert(p); + + assert(ntsc_hactive * bpp <= 0x7FF); + + *p++ = riscsync | riscsync_resync | riscsync_vre; + *p++ = 0; + + *p++ = riscsync | riscsync_fm1; + *p++ = 0; + + for (i = 0; i != ntsc_vactive / 2; i++) { + *p++ = riscwrite | ntsc_hactive * bpp | riscwrite_sol | riscwrite_eol; + *p++ = paddr + i * 2 * stride * bpp; + } + + *p++ = riscsync | riscsync_resync | riscsync_vro; + *p++ = 0; + + *p++ = riscsync | riscsync_fm1; + *p++ = 0; + + for (i = 0; i != ntsc_vactive / 2; i++) { + *p++ = riscwrite | ntsc_hactive * bpp | riscwrite_sol | riscwrite_eol; + *p++ = paddr + (i * 2 + 1) * stride * bpp; + } + + *p++ = riscjmp; + *p++ = PADDR(pbase); + USED(p); + + return pbase; +} + +static void +vstart(Tv *tv, ulong paddr, int stride) +{ + Bt848 *bt848 = tv->bt848; + ulong *program, cfmt; + int bpp; + + cfmt = bt848->colorfmt; + bpp = -1; + switch (cfmt) { + case colorfmt_rgb16: + bpp = 2; + break; + default: + panic("render: Unsupport color format\n"); + } + + program = riscprogram(paddr, stride, bpp); +// program = riscprogram(PADDR(tv->dbuf), ntsc_hactive * bpp, bpp); + + ilock(tv); + if (waserror()) { + iunlock(tv); + free(program); + nexterror(); + } + + if (tv->program) + error(Einuse); + + if (cfmt != bt848->colorfmt) + error(Eio); + + tv->program = program; + bt848->riscstrtadd = PADDR(tv->program); + bt848->capctl |= capctl_captureodd|capctl_captureeven; + bt848->gpiodmactl |= gpiodmactl_fifoenable; + bt848->gpiodmactl |= gpiodmactl_riscenable; + + poperror(); + iunlock(tv); +} + +static void +vstop(Tv *tv) +{ + Bt848 *bt848 = tv->bt848; + + ilock(tv); + if (waserror()) { + + if (tv->program) + free(tv->program); + iunlock(tv); + nexterror(); + } + + if (tv->program) { + bt848->gpiodmactl &= ~gpiodmactl_riscenable; + bt848->gpiodmactl &= ~gpiodmactl_fifoenable; + bt848->capctl &= ~(capctl_captureodd|capctl_captureeven); + + free(tv->program); + tv->program = nil; + } + + poperror(); + iunlock(tv); +} + +static long +hrcfreq[] = { /* HRC CATV frequencies */ + 0, 7200, 5400, 6000, 6600, 7800, 8400, 17400, + 18000, 18600, 19200, 19800, 20400, 21000, 12000, 12600, + 13200, 13800, 14400, 15000, 15600, 16200, 16800, 21600, + 22200, 22800, 23400, 24000, 24600, 25200, 25800, 26400, + 27000, 27600, 28200, 28800, 29400, 30000, 30600, 31200, + 31800, 32400, 33000, 33600, 34200, 34800, 35400, 36000, + 36600, 37200, 37800, 38400, 39000, 39600, 40200, 40800, + 41400, 42000, 42600, 43200, 43800, 44400, 45000, 45600, + 46200, 46800, 47400, 48000, 48600, 49200, 49800, 50400, + 51000, 51600, 52200, 52800, 53400, 54000, 54600, 55200, + 55800, 56400, 57000, 57600, 58200, 58800, 59400, 60000, + 60600, 61200, 61800, 62400, 63000, 63600, 64200, 9000, + 9600, 10200, 10800, 11400, 64800, 65400, 66000, 66600, + 67200, 67800, 68400, 69000, 69600, 70200, 70800, 71400, + 72000, 72600, 73200, 73800, 74400, 75000, 75600, 76200, + 76800, 77400, 78000, 78600, 79200, 79800, +}; + +static void +frequency(Tv *tv, int channel, int finetune) +{ + Tuner *tuner = tv->tuner; + long freq; + ushort div; + uchar cfg; + + if (channel < 0 || channel > nelem(hrcfreq)) + error(Ebadarg); + + freq = (hrcfreq[channel] * Freqmultiplier) / 100; + + if (freq < tuner->freq_vhfh) + cfg = tuner->VHF_L; + else if (freq < tuner->freq_uhf) + cfg = tuner->VHF_H; + else + cfg = tuner->UHF; + + div = (freq + tuner->offs + finetune) & 0x7fff; + + if (!i2cwrite(tv, 0xc0, (div >> 8) & 0x7f, div, 1)) + error(Eio); + + if (!i2cwrite(tv, 0xc0, tuner->cfg, cfg, 1)) + error(Eio); +} + diff --git a/pc/vgamga4xx.c b/pc/vgamga4xx.c new file mode 100644 index 0000000000000000000000000000000000000000..e581f54c0afb9d3fabf1328c8c3c1cf196882f17 --- /dev/null +++ b/pc/vgamga4xx.c @@ -0,0 +1,559 @@ + +/* + * Matrox G200, G400 and G450. + * see /sys/src/cmd/aux/vga/mga4xx.c + */ + +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "../port/error.h" + +#define Image IMAGE +#include +#include +#include +#include "screen.h" + +enum { + MATROX = 0x102B, + MGA4xx = 0x0525, + MGA200 = 0x0521, + + Kilo = 1024, + Meg = 1024*1024, + + FCOL = 0x1c24, + FXRIGHT = 0x1cac, + FXLEFT = 0x1ca8, + YDST = 0x1c90, + YLEN = 0x1c5c, + DWGCTL = 0x1c00, + DWG_TRAP = 0x04, + DWG_BITBLT = 0x08, + DWG_ILOAD = 0x09, + DWG_LINEAR = 0x0080, + DWG_SOLID = 0x0800, + DWG_ARZERO = 0x1000, + DWG_SGNZERO = 0x2000, + DWG_SHIFTZERO = 0x4000, + DWG_REPLACE = 0x000C0000, + DWG_REPLACE2 = (DWG_REPLACE | 0x40), + DWG_XOR = 0x00060010, + DWG_BFCOL = 0x04000000, + DWG_BMONOWF = 0x08000000, + DWG_TRANSC = 0x40000000, + SRCORG = 0x2cb4, + PITCH = 0x1c8c, + DSTORG = 0x2cb8, + PLNWRT = 0x1c1c, + ZORG = 0x1c0c, + MACCESS = 0x1c04, + STATUS = 0x1e14, + FXBNDRY = 0x1C84, + CXBNDRY = 0x1C80, + YTOP = 0x1C98, + YBOT = 0x1C9C, + YDSTLEN = 0x1C88, + AR0 = 0x1C60, + AR1 = 0x1C64, + AR2 = 0x1C68, + AR3 = 0x1C6C, + AR4 = 0x1C70, + AR5 = 0x1C74, + SGN = 0x1C58, + SGN_SCANLEFT = 1, + SGN_SCANRIGHT = 0, + SGN_SDY_POSITIVE = 0, + SGN_SDY_NEGATIVE = 4, + + GO = 0x0100, + FIFOSTATUS = 0x1E10, + CACHEFLUSH = 0x1FFF, + + CRTCEXTIDX = 0x1FDE, /* CRTC Extension Index */ + CRTCEXTDATA = 0x1FDF, /* CRTC Extension Data */ + + FILL_OPERAND = 0x800c7804, +}; + +static Pcidev* +mgapcimatch(void) +{ + Pcidev* p; + + p = pcimatch(nil, MATROX, MGA4xx); + if (p == nil) + p = pcimatch(nil, MATROX, MGA200); + return p; +} + +static ulong +mga4xxlinear(VGAscr* scr, int* size, int* align) +{ + ulong aperture, oaperture; + int oapsize, wasupamem; + Pcidev * p; + + oaperture = scr->aperture; + oapsize = scr->apsize; + wasupamem = scr->isupamem; + + if(p = mgapcimatch()){ + aperture = p->mem[0].bar & ~0x0F; + if(p->did == MGA4xx) + *size = 32*Meg; + else + *size = 8*Meg; + } + else + aperture = 0; + + if(wasupamem) { + if(oaperture == aperture) + return oaperture; + upafree(oaperture, oapsize); + } + scr->isupamem = 0; + + aperture = upamalloc(aperture, *size, *align); + if(aperture == 0){ + if(wasupamem && upamalloc(oaperture, oapsize, 0)) { + aperture = oaperture; + scr->isupamem = 1; + } + else + scr->isupamem = 0; + } + else + scr->isupamem = 1; + + return aperture; +} + +static void +mgawrite8(VGAscr* scr, int index, uchar val) +{ + ((uchar*)scr->io)[index] = val; +} + +static uchar +mgaread8(VGAscr* scr, int index) +{ + return ((uchar*)scr->io)[index]; +} + +static uchar +crtcextset(VGAscr* scr, int index, uchar set, uchar clr) +{ + uchar tmp; + + mgawrite8(scr, CRTCEXTIDX, index); + tmp = mgaread8(scr, CRTCEXTDATA); + mgawrite8(scr, CRTCEXTIDX, index); + mgawrite8(scr, CRTCEXTDATA, (tmp & ~clr) | set); + + return tmp; +} + +static void +mga4xxenable(VGAscr* scr) +{ + Pcidev * pci; + int size, align; + ulong aperture; + int i, n, k; + uchar * p; + uchar x[16]; + uchar crtcext3; + + /* + * Only once, can't be disabled for now. + * scr->io holds the virtual address of + * the MMIO registers. + */ + if(scr->io) + return; + + pci = mgapcimatch(); + if(pci == nil) + return; + + scr->io = upamalloc(pci->mem[1].bar & ~0x0F, 16*1024, 0); + if(scr->io == 0) + return; + + addvgaseg("mga4xxmmio", scr->io, pci->mem[1].size); + + scr->io = (ulong)KADDR(scr->io); + + /* need to map frame buffer here too, so vga can find memory size */ + size = 8*Meg; + align = 0; + aperture = mga4xxlinear(scr, &size, &align); + if(aperture) { + scr->aperture = aperture; + addvgaseg("mga4xxscreen", aperture, size); + + /* Find out how much memory is here, some multiple of 2 Meg */ + + /* First Set MGA Mode ... */ + crtcext3 = crtcextset(scr, 3, 0x80, 0x00); + + p = (uchar*)aperture; + n = (size / Meg) / 2; + for (i = 0; i < n; i++) { + k = (2*i+1)*Meg; + p[k] = 0; + p[k] = i+1; + *((uchar*)(scr->io + CACHEFLUSH)) = 0; + x[i] = p[k]; + } + for(i = 1; i < n; i++) + if(x[i] != i+1) + break; + scr->apsize = 2*i*Meg; + + crtcextset(scr, 3, crtcext3, 0xff); + } +} + +enum { + Index = 0x00, /* Index */ + Data = 0x0A, /* Data */ + + Cxlsb = 0x0C, /* Cursor X LSB */ + Cxmsb = 0x0D, /* Cursor X MSB */ + Cylsb = 0x0E, /* Cursor Y LSB */ + Cymsb = 0x0F, /* Cursor Y MSB */ + + Icuradrl = 0x04, /* Cursor Base Address Low */ + Icuradrh = 0x05, /* Cursor Base Address High */ + Icctl = 0x06, /* Indirect Cursor Control */ +}; + +static void +dac4xxdisable(VGAscr* scr) +{ + uchar * dac4xx; + + if(scr->io == 0) + return; + + dac4xx = KADDR(scr->io+0x3C00); + + *(dac4xx+Index) = Icctl; + *(dac4xx+Data) = 0x00; +} + +static void +dac4xxload(VGAscr* scr, Cursor* curs) +{ + int y; + uchar * p; + uchar * dac4xx; + + if(scr->io == 0) + return; + + dac4xx = KADDR(scr->io+0x3C00); + + dac4xxdisable(scr); + + p = KADDR(scr->storage); + for(y = 0; y < 64; y++){ + *p++ = 0; *p++ = 0; *p++ = 0; + *p++ = 0; *p++ = 0; *p++ = 0; + if(y <16){ + *p++ = curs->set[1+y*2]|curs->clr[1+2*y]; + *p++ = curs->set[y*2]|curs->clr[2*y]; + } else{ + *p++ = 0; *p++ = 0; + } + + *p++ = 0; *p++ = 0; *p++ = 0; + *p++ = 0; *p++ = 0; *p++ = 0; + if(y <16){ + *p++ = curs->set[1+y*2]; + *p++ = curs->set[y*2]; + } else{ + *p++ = 0; *p++ = 0; + } + } + scr->offset.x = 64 + curs->offset.x; + scr->offset.y = 64 + curs->offset.y; + + *(dac4xx+Index) = Icctl; + *(dac4xx+Data) = 0x03; +} + +static int +dac4xxmove(VGAscr* scr, Point p) +{ + int x, y; + uchar * dac4xx; + + if(scr->io == 0) + return 1; + + dac4xx = KADDR(scr->io + 0x3C00); + + x = p.x + scr->offset.x; + y = p.y + scr->offset.y; + + *(dac4xx+Cxlsb) = x & 0xFF; + *(dac4xx+Cxmsb) = (x>>8) & 0x0F; + + *(dac4xx+Cylsb) = y & 0xFF; + *(dac4xx+Cymsb) = (y>>8) & 0x0F; + + return 0; +} + +static void +dac4xxenable(VGAscr* scr) +{ + uchar * dac4xx; + ulong storage; + + if(scr->io == 0) + return; + dac4xx = KADDR(scr->io+0x3C00); + + dac4xxdisable(scr); + + storage = (scr->apsize - 4096) & ~0x3ff; + + *(dac4xx+Index) = Icuradrl; + *(dac4xx+Data) = 0xff & (storage >> 10); + *(dac4xx+Index) = Icuradrh; + *(dac4xx+Data) = 0xff & (storage >> 18); + + scr->storage = (ulong) KADDR((ulong)scr->aperture + (ulong)storage); + + /* Show X11-Like Cursor */ + *(dac4xx+Index) = Icctl; + *(dac4xx+Data) = 0x03; + + /* Cursor Color 0 : White */ + *(dac4xx+Index) = 0x08; + *(dac4xx+Data) = 0xff; + *(dac4xx+Index) = 0x09; + *(dac4xx+Data) = 0xff; + *(dac4xx+Index) = 0x0a; + *(dac4xx+Data) = 0xff; + + /* Cursor Color 1 : Black */ + *(dac4xx+Index) = 0x0c; + *(dac4xx+Data) = 0x00; + *(dac4xx+Index) = 0x0d; + *(dac4xx+Data) = 0x00; + *(dac4xx+Index) = 0x0e; + *(dac4xx+Data) = 0x00; + + /* Cursor Color 2 : Red */ + *(dac4xx+Index) = 0x10; + *(dac4xx+Data) = 0xff; + *(dac4xx+Index) = 0x11; + *(dac4xx+Data) = 0x00; + *(dac4xx+Index) = 0x12; + *(dac4xx+Data) = 0x00; + + /* + * Load, locate and enable the + * 64x64 cursor in X11 mode. + */ + dac4xxload(scr, &arrow); + dac4xxmove(scr, ZP); +} + +static void +mga4xxblank(VGAscr* scr, int blank) +{ + char * cp; + uchar * mga; + uchar seq1, crtcext1; + + /* blank = 0 -> turn screen on */ + /* blank = 1 -> turn screen off */ + + if(scr->io == 0) + return; + mga = KADDR(scr->io); + + if (blank == 0) { + seq1 = 0x00; + crtcext1 = 0x00; + } else { + seq1 = 0x20; + crtcext1 = 0x10; /* Default value ... : standby */ + cp = getconf("*dpms"); + if (cp) { + if (cistrcmp(cp, "standby") == 0) { + crtcext1 = 0x10; + } else if (cistrcmp(cp, "suspend") == 0) { + crtcext1 = 0x20; + } else if (cistrcmp(cp, "off") == 0) { + crtcext1 = 0x30; + } + } + } + + *(mga + 0x1fc4) = 1; + seq1 |= *(mga + 0x1fc5) & ~0x20; + *(mga + 0x1fc5) = seq1; + + *(mga + 0x1fde) = 1; + crtcext1 |= *(mga + 0x1fdf) & ~0x30; + *(mga + 0x1fdf) = crtcext1; +} + +static void +mgawrite32(uchar * mga, ulong reg, ulong val) +{ + ulong * l; + + l = (ulong *)(&mga[reg]); + l[0] = val; +} + +static ulong +mgaread32(uchar * mga, ulong reg) +{ + return *((ulong *)(&mga[reg])); +} + +static int +mga4xxfill(VGAscr* scr, Rectangle r, ulong color) +{ + uchar * mga; + + /* Constant Shaded Trapezoids / Rectangle Fills */ + if(scr->io == 0) + return 0; + mga = KADDR(scr->io); + + mgawrite32(mga, DWGCTL, 0); + mgawrite32(mga, FCOL, color); + mgawrite32(mga, FXRIGHT, r.max.x); + mgawrite32(mga, FXLEFT, r.min.x); + mgawrite32(mga, YDST, r.min.y); + mgawrite32(mga, YLEN, Dy(r)); + mgawrite32(mga, DWGCTL + GO, FILL_OPERAND); + + while (mgaread32(mga, STATUS) & 0x00010000) + ; + return 1; +} + +#define mga_fifo(n) do {} while ((mgaread32(mga, FIFOSTATUS) & 0xFF) < (n)) + +static int +mga4xxscroll(VGAscr* scr, Rectangle r_dst, Rectangle r_src) +{ + uchar * mga; + ulong pitch; + ulong w, h, start, end, y; + + /* Two-operand Bitblts */ + if(scr->io == 0) + return 0; + mga = KADDR(scr->io); + + pitch = Dx(scr->gscreen->r); + + mgawrite32(mga, DWGCTL, 0); + h = Dy(r_src); + w = Dx(r_src); + y = r_dst.min.y; + + if ((r_dst.min.y < r_src.min.y) || + ((r_dst.min.y == r_src.min.y) && (r_dst.min.x <= r_src.min.y))) { + mga_fifo(2); + mgawrite32(mga, DWGCTL, DWG_BITBLT | DWG_SHIFTZERO | + DWG_SGNZERO | DWG_BFCOL | DWG_REPLACE); + mgawrite32(mga, AR5, pitch); + w--; + start = r_src.min.y*pitch+r_src.min.x; + end = start+w; + } else { + mga_fifo(3); + mgawrite32(mga, DWGCTL, DWG_BITBLT | DWG_SHIFTZERO | + DWG_BFCOL | DWG_REPLACE); + mgawrite32(mga, SGN, 5); + mgawrite32(mga, AR5, (-pitch) & 0x3ffff); + w--; + end = (r_src.min.y+h-1)*pitch+r_src.min.x; + start = end+w; + y += h-1; + } + mga_fifo(4); + mgawrite32(mga, AR0, end); + mgawrite32(mga, AR3, start); + mgawrite32(mga, FXBNDRY, ((r_dst.min.x+w)<<16) | r_dst.min.x); + mgawrite32(mga, YDST, y); + mgawrite32(mga, YLEN + GO, h); + + while (mgaread32(mga, STATUS) & 0x00010000) + ; + return 1; +} + +static void +mga4xxdrawinit(VGAscr* scr) +{ + uchar * mga; + Pcidev* p; + + p = pcimatch(nil, MATROX, MGA4xx); + if (p == nil) + return ; + + if(scr->io == 0) + return; + mga = KADDR(scr->io); + + mgawrite32(mga, SRCORG, 0); + mgawrite32(mga, DSTORG, 0); + mgawrite32(mga, ZORG, 0); + mgawrite32(mga, PLNWRT, ~0); + mgawrite32(mga, FCOL, 0xffff0000); + mgawrite32(mga, CXBNDRY, 0xFFFF0000); + mgawrite32(mga, YTOP, 0); + mgawrite32(mga, YBOT, 0x01FFFFFF); + mgawrite32(mga, PITCH, Dx(scr->gscreen->r) & ((1 << 13) - 1)); + switch(scr->gscreen->depth) { + case 8: + mgawrite32(mga, MACCESS, 0); + break; + case 32: + mgawrite32(mga, MACCESS, 2); + break; + default: + return; /* depth not supported ! */ + } + scr->fill = mga4xxfill; + scr->scroll = mga4xxscroll; + scr->blank = mga4xxblank; +} + +VGAdev vgamga4xxdev = { + "mga4xx", + + mga4xxenable, /* enable */ + 0, /* disable */ + 0, /* page */ + mga4xxlinear, /* linear */ + mga4xxdrawinit, +}; + +VGAcur vgamga4xxcur = { + "mga4xxhwgc", + dac4xxenable, + dac4xxdisable, + dac4xxload, + dac4xxmove, +}; diff --git a/port/devbridge.c b/port/devbridge.c index 0ff308fd8dc64742472db64705df48a9414b6815..e95302c368a9c2e4f4cad81b5ec1f4bc49381874 100644 --- a/port/devbridge.c +++ b/port/devbridge.c @@ -437,7 +437,7 @@ bridgegen(Chan *c, char *, Dirtab*, int, int s, Dir *dp) devdir(c, qid, up->genbuf, 0, eve, 0555, dp); break; default: - panic("bridgewalk %lux", c->qid.path); + panic("bridgewalk %llux", c->qid.path); } return 1; } @@ -451,7 +451,7 @@ bridgegen(Chan *c, char *, Dirtab*, int, int s, Dir *dp) return -1; dt = dirtab[TYPE(c->qid)]; if(dt == nil) - panic("bridgegen: unknown type: %d", TYPE(c->qid)); + panic("bridgegen: unknown type: %lud", TYPE(c->qid)); devdir(c, c->qid, dt->name, dt->length, eve, dt->perm, dp); return 1; case Qtopdir: diff --git a/port/devloopback.c b/port/devloopback.c index 53d5263ee4fa24fa75ce4df6301720c7fe33a6d6..f05df7a444a94fd0aa5d5fae7031f31806f2fd0e 100644 --- a/port/devloopback.c +++ b/port/devloopback.c @@ -208,7 +208,7 @@ loopbackgen(Chan *c, char*, Dirtab*, int, int i, Dir *dp) devdir(c, qid, up->genbuf, 0, eve, 0555, dp); break; default: - panic("loopbackgen %lux", c->qid.path); + panic("loopbackgen %llux", c->qid.path); } return 1; } diff --git a/port/devsdp.c b/port/devsdp.c index 8a02c7f3b3dbb77af26de0bb85ef82645ce079a6..c1a9ca242529247647c7c5c293442f5a2bd93191 100644 --- a/port/devsdp.c +++ b/port/devsdp.c @@ -723,7 +723,7 @@ sdpgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp) devdir(c, qid, up->genbuf, 0, eve, 0555, dp); break; default: - panic("sdpwalk %lux", c->qid.path); + panic("sdpwalk %llux", c->qid.path); } return 1; } @@ -737,7 +737,7 @@ sdpgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp) return -1; dt = dirtab[TYPE(c->qid)]; if(dt == nil) - panic("sdpgen: unknown type: %d", TYPE(c->qid)); + panic("sdpgen: unknown type: %lud", TYPE(c->qid)); devdir(c, c->qid, dt->name, dt->length, eve, dt->perm, dp); return 1; case Qtopdir: