From 0ae1ad81d8abfc17b5f227de54b1ac95392e143b Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Fri, 10 Nov 2000 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 2000-11-10 --- bitsy/clock.c | 17 +++ bitsy/devuda1341.c | 306 +++++++++++++++++++++++++++------------------ bitsy/fns.h | 7 +- bitsy/io.h | 23 ++++ bitsy/main.c | 46 +++++++ bitsy/sa1110dma.c | 23 +++- bitsy/sa1110dma.h | 13 ++ pc/devether.c | 2 +- pc/devi82365.c | 1 - 9 files changed, 305 insertions(+), 133 deletions(-) create mode 100644 bitsy/sa1110dma.h diff --git a/bitsy/clock.c b/bitsy/clock.c index c50bae830c913d21e42c9661125c8e60c7e1e843..c032b1d3df228794882ef1b4f09e7c6b576edb84 100644 --- a/bitsy/clock.c +++ b/bitsy/clock.c @@ -66,3 +66,20 @@ delay(int ms) } } } + +void +µdelay(int µs) +{ + ulong start; + int i; + + if(clockinited){ + start = timerregs->oscr; + while(timerregs->oscr - start < µs∗ClockFreq/1000000); + } else { + while(µs-- > 0){ + for(i = 0; i < 10; i++) + ; + } + } +} diff --git a/bitsy/devuda1341.c b/bitsy/devuda1341.c index 9dde170ba373acdbaa6d662b167bed0a2f07739d..59a354814430cb15b903561cf462a6837a971060 100644 --- a/bitsy/devuda1341.c +++ b/bitsy/devuda1341.c @@ -17,6 +17,7 @@ #include "fns.h" #include "../port/error.h" #include "io.h" +#include "sa1110dma.h" /* * GPIO based L3 bus support. @@ -122,7 +123,6 @@ audiodir[] = struct Buf { - int active; /* dma running */ uchar* virt; uint nbytes; }; @@ -130,11 +130,15 @@ struct Buf struct IOstate { QLock; - Rendez vous; - int bufinit; /* boolean, if buffers allocated */ - Buf buf[Nbuf]; /* buffers and queues */ - Buf *current; /* next candidate for dma */ - Buf *filling; /* buffer being filled */ + Rendez vous; + Chan *chan; /* chan of open */ + int dma; /* dma chan, alloc on open, free on close */ + int bufinit; /* boolean, if buffers allocated */ + Buf buf[Nbuf]; /* buffers and queues */ + int active; /* # of dmas in progress */ + volatile Buf *current; /* next dma to finish */ + volatile Buf *next; /* next candidate for dma */ + volatile Buf *filling; /* buffer being filled */ }; static struct @@ -177,29 +181,32 @@ static struct /* * Grab control of the IIC/L3 shared pins */ -static void L3_acquirepins(void) +static void +L3_acquirepins(void) { - GPSR = (GPIO_L3_SCLK_o | GPIO_L3_SDA_io); - GPDR |= (GPIO_L3_SCLK_o | GPIO_L3_SDA_io); + gpioregs->set = (GPIO_L3_SCLK_o | GPIO_L3_SDA_io); + gpioregs->direction |= (GPIO_L3_SCLK_o | GPIO_L3_SDA_io); } /* * Release control of the IIC/L3 shared pins */ -static void L3_releasepins(void) +static void +L3_releasepins(void) { - GPDR &= ~(GPIO_L3_SCLK_o | GPIO_L3_SDA_io); - GPCR = (GPIO_L3_SCLK_o | GPIO_L3_SDA_io); + gpioregs->direction &= ~(GPIO_L3_SCLK_o | GPIO_L3_SDA_io); + gpioregs->clear = (GPIO_L3_SCLK_o | GPIO_L3_SDA_io); } /* * Initialize the interface */ -static void __init L3_init(void) +static void +L3_init(void) { - GAFR &= ~(GPIO_L3_SDA_io | GPIO_L3_SCLK_o | GPIO_L3_MODE_o); - GPSR = GPIO_L3_MODE_o; - GPDR |= GPIO_L3_MODE_o; + gpioregs->altfunc &= ~(GPIO_L3_SDA_io | GPIO_L3_SCLK_o | GPIO_L3_MODE_o); + gpioregs->set = GPIO_L3_MODE_o; + gpioregs->direction |= GPIO_L3_MODE_o; L3_releasepins(); } @@ -207,17 +214,18 @@ static void __init L3_init(void) * Get a bit. The clock is high on entry and on exit. Data is read after * the clock low time has expired. */ -static int L3_getbit(void) +static int +L3_getbit(void) { int data; - GPCR = GPIO_L3_SCLK_o; - udelay(L3_ClockLowTime); + gpioregs->clear = GPIO_L3_SCLK_o; + µdelay(L3_ClockLowTime); - data = (GPLR & GPIO_L3_SDA_io) ? 1 : 0; + data = (gpioregs->level & GPIO_L3_SDA_io) ? 1 : 0; - GPSR = GPIO_L3_SCLK_o; - udelay(L3_ClockHighTime); + gpioregs->set = GPIO_L3_SCLK_o; + µdelay(L3_ClockHighTime); return data; } @@ -226,20 +234,21 @@ static int L3_getbit(void) * Send a bit. The clock is high on entry and on exit. Data is sent only * when the clock is low (I2C compatibility). */ -static void L3_sendbit(int bit) +static void +L3_sendbit(int bit) { - GPCR = GPIO_L3_SCLK_o; + gpioregs->clear = GPIO_L3_SCLK_o; if (bit & 1) - GPSR = GPIO_L3_SDA_io; + gpioregs->set = GPIO_L3_SDA_io; else - GPCR = GPIO_L3_SDA_io; + gpioregs->clear = GPIO_L3_SDA_io; /* Assumes L3_DataSetupTime < L3_ClockLowTime */ - udelay(L3_ClockLowTime); + µdelay(L3_ClockLowTime); - GPSR = GPIO_L3_SCLK_o; - udelay(L3_ClockHighTime); + gpioregs->set = GPIO_L3_SCLK_o; + µdelay(L3_ClockHighTime); } /* @@ -247,34 +256,35 @@ static void L3_sendbit(int bit) * count. The mode line is high on entry and exit. The mod line is pulsed * before the second data byte and before ech byte thereafter. */ -static void L3_sendbyte(char data, int mode) +static void +L3_sendbyte(char data, int mode) { int i; L3_acquirepins(); switch(mode) { - case 0: /* Address mode */ - GPCR = GPIO_L3_MODE_o; + case 0: /* Address mode */ + gpioregs->clear = GPIO_L3_MODE_o; break; - case 1: /* First data byte */ + case 1: /* First data byte */ break; - default: /* Subsequent bytes */ - GPCR = GPIO_L3_MODE_o; - udelay(L3_HaltTime); - GPSR = GPIO_L3_MODE_o; + default: /* Subsequent bytes */ + gpioregs->clear = GPIO_L3_MODE_o; + µdelay(L3_HaltTime); + gpioregs->set = GPIO_L3_MODE_o; break; } - udelay(L3_ModeSetupTime); + µdelay(L3_ModeSetupTime); for (i = 0; i < 8; i++) L3_sendbit(data >> i); if (mode == 0) /* Address mode */ - GPSR = GPIO_L3_MODE_o; + gpioregs->set = GPIO_L3_MODE_o; - udelay(L3_ModeHoldTime); + µdelay(L3_ModeHoldTime); L3_releasepins(); } @@ -286,32 +296,33 @@ static void L3_sendbyte(char data, int mode) * function is never valid with mode == 0 (address cycle) as the address * is always sent on the bus, not read. */ -static char L3_getbyte(int mode) +static char +L3_getbyte(int mode) { char data = 0; int i; L3_acquirepins(); - GPDR &= ~(GPIO_L3_SDA_io); + gpioregs->direction &= ~(GPIO_L3_SDA_io); switch(mode) { - case 0: /* Address mode - never valid */ + case 0: /* Address mode - never valid */ break; - case 1: /* First data byte */ + case 1: /* First data byte */ break; - default: /* Subsequent bytes */ - GPCR = GPIO_L3_MODE_o; - udelay(L3_HaltTime); - GPSR = GPIO_L3_MODE_o; + default: /* Subsequent bytes */ + gpioregs->clear = GPIO_L3_MODE_o; + µdelay(L3_HaltTime); + gpioregs->set = GPIO_L3_MODE_o; break; } - udelay(L3_ModeSetupTime); + µdelay(L3_ModeSetupTime); for (i = 0; i < 8; i++) data |= (L3_getbit() << i); - udelay(L3_ModeHoldTime); + µdelay(L3_ModeHoldTime); L3_releasepins(); @@ -324,7 +335,8 @@ static char L3_getbyte(int mode) * is encoded in the address (low two bits are set and device address is * in the upper 6 bits). */ -static int L3_write(char addr, char *data, int len) +static int +L3_write(char addr, char *data, int len) { int mode = 0; int bytes = len; @@ -342,7 +354,8 @@ static int L3_write(char addr, char *data, int len) * is encoded in the address (low two bits are set and device address is * in the upper 6 bits). */ -static int L3_read(char addr, char * data, int len) +static int +L3_read(char addr, char * data, int len) { int mode = 0; int bytes = len; @@ -378,27 +391,70 @@ setempty(IOstate *b) } b->filling = b->buf; b->current = b->buf; + b->next = b->buf; +} + +static int +audioqnotfull(IOstate *s) +{ + /* called with lock */ + return s->active == 0 || s->filling != s->current; +} + +static int +audioqnotempty(IOstate *s) +{ + /* called with lock */ + return s->next != s->filling; +} + +static int +audioidle(IOstate *s) +{ + /* called with lock */ + return s->active == 0; } static void audioinit(void) +{ + /* do nothing */ +} + +static void +audioenable(void) { int err; - - /* Acquire and initialize DMA */ - if( audio_init_dma( &output_stream, "UDA1341 DMA out" ) || - audio_init_dma( &input_stream, "UDA1341 DMA in" ) ){ - audio_clear_dma( &output_stream ); - audio_clear_dma( &input_stream ); - return -EBUSY; - } L3_init(); - audio_ssp_init(); - audio_uda1341_reset(); + /* Setup the uarts */ + ppcregs->assignment &= ~(1<<18); /* Could be the other way round! */ - init_waitqueue_head(&audio_waitq); + gpioregs->altfunc &= ~(GPIO_SSP_TXD | GPIO_SSP_RXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM); + gpioregs->altfunc |= (GPIO_SSP_CLK); + gpioregs->direction &= ~(GPIO_SSP_CLK); + + sspregs->control0 = 0x10<<0 | 0x1<<4 | 1<<7 | 0x8<<8; + sspregs->control1 = 0<<3 + 0<<4 + 1<<5; + + /* Enable the audio power */ + set_bitsy_egpio(EGPIO_BITSY_CODEC_NRESET|EGPIO_BITSY_AUD_AMP_ON|EGPIO_BITSY_AUD_PWR_ON); + clr_bitsy_egpio(EGPIO_BITSY_QMUTE); + gpioregs->direction |= (GPIO_BITSY_CLK_SET0|GPIO_BITSY_CLK_SET1); + /* external clock configured for 44100 samples/sec */ + GPSR = GPIO_BITSY_CLK_SET0; + GPCR = GPIO_BITSY_CLK_SET1; + + + printk("gpioregs->altfunc=%08x gpioregs->direction=%08x GPLR=%08x\n", gpioregs->altfunc, gpioregs->direction, GPLR); + printk("PPDR=%08x PPSR=%08x PPAR=%08x PPFR=%08x\n", PPDR, PPSR, PPAR, PPFR); + + /* Wait for the UDA1341 to wake up */ + mdelay(100); + printk("Ser4SSSR=%08x\n", Ser4SSSR); + + audio_uda1341_reset(); /* Set some default mixer values... */ STATUS_1.DAC_gain = 1; @@ -416,23 +472,42 @@ audioinit(void) DATA0_ext6.AGC_level = 3; L3_write( (UDA1341_L3Addr<<2)|UDA1341_DATA0, (char*)&DATA0_ext6, 2 ); - /* register devices */ - audio_dev_dsp = register_sound_dsp(&UDA1341_dsp_fops, -1); - audio_dev_mixer = register_sound_mixer(&UDA1341_mixer_fops, -1); - - printk( AUDIO_NAME_VERBOSE " initialized\n" ); + print("audio enabled\n"); return 0; } static void sendaudio(IOstat *b) { - if (dmastart(b->chan, b->current->virt, b->current->nbytes)) { - b->current->active++; - b->current++; + /* call this with lock held */ + while (b->next != b->filling) { + assert(b->next->nbytes); + if (dmastart(b->dma, b->next->virt, b->next->nbytes) == 0) + break; + incref(&b->active); + b->next++; + if (b->next == &b->buf[Nbuf]) + b->next == &b->buf[0]; + } +} + +static void +audiointr(void *x, ulong state) { + IOstate *s = x; + + if (s == &audio.o) { + decref(&s->active); + /* Only interrupt routine touches s->current */ + s->current->nbytes = 0; + s->current++; if (b->current == &b->buf[Nbuf]) b->current == &b->buf[0]; + if (canlock(s)) { + sendaudio(s); + unlock(s); + } } + wakeup(s->vous); } static Chan* @@ -471,26 +546,33 @@ audioopen(Chan *c, int omode) case Qaudio: omode = (omode & 0x7) + 1; - if (omode & ~(Aread | Awrite)) +// if (omode & ~(Aread | Awrite)) + if (omode & ~(Awrite)) error(Ebadarg); qlock(&audio); if(audio.amode & omode){ qunlock(&audio); error(Einuse); } + audiopower(1); if (omode & Aread) { /* read */ audio.amode |= Aread; if(audio.i.bufinit == 0) bufinit(&audio.i); + audio.i.chan = c; setempty(&audio.i); } if (omode & 0x2) { /* write */ + amplifierpower(1); + audiomute(0); audio.amode |= Awrite; if(audio.o.bufinit == 0) bufinit(&audio.o); setempty(&audio.o); + audio.o.chan = c; + &audio.o.dma = dmaalloc(0, 0, 8, 2, AudioDMA, void *port, void (*f)(int, ulong)) } qunlock(&audio); // mxvolume(); @@ -507,7 +589,7 @@ audioopen(Chan *c, int omode) static void audioclose(Chan *c) { - Buf *b; + IOstate *b; switch(c->qid.path & ~CHDIR) { default: @@ -522,22 +604,38 @@ audioclose(Chan *c) case Qaudio: if(c->flag & COPEN) { qlock(&audio); - if(audio.amode & Awrite) { - /* flush out last partial buffer */ - b = audio.o.filling; - if(audio.o.buf[b].count) { - putbuf(&audio.full, b); - } - } - audio.amode = Aclosed; + qlock(&audio.o); if(waserror()){ + qunlock(&audio.o); qunlock(&audio); nexterror(); } - while(audio.active) - waitaudio(); - setempty(); + if (audio.o.chan == c) { + /* closing the write end */ + audio.amode &= ~Awrite; + + while (audio.o.filling->nbytes) { + audio.o.filling++; + if (audio.o.filling == &audio.o.buf[Nbuf]) + audio.o.filling = &audio.o.buf[0]; + sendaudio(&audio.o); + } + while(!audioidle(&audio.o)) + sleep(&audio.o.vous, audioidle, &audio.o); + audioamplifier(0); + setempty(&audio.o); + } + if (audio.i.chan == c) { + /* closing the read end */ + audio.amode &= ~Aread; + setempty(&audio.i); + } + if (audio.amode == 0) { + /* turn audio off */ + audiopower(0); + } poperror(); + qunlock(&audio.o); qunlock(&audio); } break; @@ -566,40 +664,6 @@ audioread(Chan *c, void *v, long n, vlong off) return devdirread(c, a, n, audiodir, nelem(audiodir), devgen); case Qaudio: - if(audio.amode != Aread) - error(Emode); - qlock(&audio); - if(waserror()){ - qunlock(&audio); - nexterror(); - } - while(n > 0) { - b = audio.filling; - if(b == 0) { - b = getbuf(&audio.full); - if(b == 0) { - waitaudio(); - continue; - } - audio.filling = b; - swab(b->virt); - audio.curcount = 0; - } - m = Bufsize-audio.curcount; - if(m > n) - m = n; - memmove(a, b->virt+audio.curcount, m); - - audio.curcount += m; - n -= m; - a += m; - if(audio.curcount >= Bufsize) { - audio.filling = 0; - putbuf(&audio.empty, b); - } - } - poperror(); - qunlock(&audio); break; case Qstatus: @@ -752,8 +816,8 @@ audiowrite(Chan *c, void *vp, long n, vlong) } while(n > 0) { /* wait if dma in progress */ - while (a->filling->active) - waitaudio(a); + while (a->active && a->filling == a->current) + sleep(&a->vous, audioqnotfull, a); m = Bufsize - a->filling->nbytes; if(m > n) @@ -764,10 +828,10 @@ audiowrite(Chan *c, void *vp, long n, vlong) n -= m; p += m; if(a->filling->nbytes >= Bufsize) { - sendaudio(a); a->filling++; if (a->filling == &a->buf[Nbuf]) a->filling = a->buf; + sendaudio(a); } } poperror(); diff --git a/bitsy/fns.h b/bitsy/fns.h index 89b62cb5aacce9311b4d4e745bbedb8e38fa2215..81eaab1fde6a4cc80f05d6652bd310f880049a14 100644 --- a/bitsy/fns.h +++ b/bitsy/fns.h @@ -10,12 +10,7 @@ int cistrncmp(char*, char*, int); void clockinit(void); #define coherence() void delay(int); -void dmainit(void); -int dmaalloc(int, int, int, int, int, void *); -void dmafree(int); -ulong dmastart(int, void *, int); -ulong dmadone(int, ulong); -void dmawait(int, ulong); +void µdelay(int); void evenaddr(ulong); void flushmmu(void); int fpiarm(Ureg *ur); diff --git a/bitsy/io.h b/bitsy/io.h index 6c50da230543e2a0a4b55bcc92358b02a5edaf45..499bd3c033a100439c50ac64eb9d024fe2da7aeb 100644 --- a/bitsy/io.h +++ b/bitsy/io.h @@ -199,3 +199,26 @@ enum EGPIO_lcd_9v= 1<<15, }; extern ulong *egpioreg; + +/* Peripheral pin controller registers */ +typedef struct PPCregs PPCregs; +struct PPCregs { + ulong direction; + ulong state; + ulong assignment; + ulong sleepdir; + ulong flags; +}; +extern PPCregs *ppcregs; + +/* Synchronous Serial Port controller registers */ +typedef struct SSPregs SSPregs; +struct SSPregs { + ulong control0; + ulong control1; + ulong dummy0; + ulong data; + ulong dummy1; + ulong status; +}; +extern SSPregs *sspregs; diff --git a/bitsy/main.c b/bitsy/main.c index 66834c76cdb59975a363d05b7da25903c709861b..819d74fabe12011b3eb6af10d41a05056fdd9d68 100644 --- a/bitsy/main.c +++ b/bitsy/main.c @@ -36,6 +36,8 @@ main(void) xinit(); mmuinit(); gpioinit(); + ppcinit(); + sspinit(); trapinit(); sa1100_uartsetup(1); rs232power(1); @@ -374,6 +376,20 @@ gpioinit(void) egpioreg = mapspecial(EGPIOREGS, 4); } +PPCregs *ppcregs; + +static void +ppcinit(void) { + ppcregs = mapspecial(PPCREGS, 32); +} + +SSPregs *sspregs; + +static void +sspinit(void) { + sspregs = mapspecial(SSPREGS, 32); +} + static ulong egpiosticky; void @@ -405,3 +421,33 @@ lcdpower(int on) egpiosticky &= ~(EGPIO_lcd_3v|EGPIO_lcd_ic_power|EGPIO_lcd_5v|EGPIO_lcd_9v); *egpioreg = egpiosticky; } + +void +audiopower(int on) +{ + if(on) + egpiosticky |= EGPIO_audio_ic_power | EGPIO_codec_reset; + else + egpiosticky &= ~(EGPIO_audio_ic_power | EGPIO_codec_reset); + *egpioreg = egpiosticky; +} + +void +amplifierpower(int on) +{ + if(on) + egpiosticky |= EGPIO_audio_power; + else + egpiosticky &= ~(EGPIO_audio_power); + *egpioreg = egpiosticky; +} + +void +audiomute(int on) +{ + if(on) + egpiosticky |= EGPIO_audio_mute; + else + egpiosticky &= ~(EGPIO_audio_mute); + *egpioreg = egpiosticky; +} diff --git a/bitsy/sa1110dma.c b/bitsy/sa1110dma.c index a22a45b652f04cea35620f5b65ea7f3a32ea9177..140300ddfcb607a4f196ecf6b6bbb1801f2646f1 100644 --- a/bitsy/sa1110dma.c +++ b/bitsy/sa1110dma.c @@ -5,6 +5,7 @@ #include "fns.h" #include "io.h" #include "../port/error.h" +#include "sa1110dma.h" /* * DMA helper routines @@ -40,7 +41,8 @@ enum { typedef struct Chan { int inuse; Rendez r; - void (*f)(void); + void (*intr)(int, ulong); + void *param; } Chan; struct { @@ -66,7 +68,7 @@ dmainit(void) { } int -dmaalloc(int rd, int bigendian, int burstsize, int datumsize, int device, void *port) { +dmaalloc(int rd, int bigendian, int burstsize, int datumsize, int device, void *port, void (*intr)(int, ulong), void *param) { int i; lock(&dma); @@ -82,6 +84,8 @@ dmaalloc(int rd, int bigendian, int burstsize, int datumsize, int device, void * ((datumsize==2)?1:0)<irq is less than 0, it is a hack to indicate no interrupt - * used for the seocnd logical ethernet for the wavelan card + * used for the second logical ethernet for the wavelan card */ if(ether->irq >= 0) intrenable(ether->irq, ether->interrupt, ether, ether->tbdf, name); diff --git a/pc/devi82365.c b/pc/devi82365.c index fbdd3ef7e1502a2a03c1e08eb12a56dd66f0551f..520218dd110554eb2cb8ac0cfb57ed2dd6b623a6 100644 --- a/pc/devi82365.c +++ b/pc/devi82365.c @@ -1498,6 +1498,5 @@ tvers1(Slot *pp, Cisdat *cis, int ) break; pp->verstr[i] = c; } -print("pcmcia: %s\n", pp->verstr); pp->verstr[i] = 0; }