M bitsy/devuda1341.c => bitsy/devuda1341.c +50 -58
@@ 138,7 138,6 @@ struct IOstate
int dma; /* dma chan, alloc on open, free on close */
int bufinit; /* boolean, if buffers allocated */
Buf buf[Nbuf]; /* buffers and queues */
- Ref 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 */
@@ 159,6 158,14 @@ static struct
IOstate o;
} audio;
+static struct
+{
+ ulong bytes;
+ ulong totaldma;
+ ulong idledma;
+ ulong faildma;
+} iostats;
+
static struct
{
char* name;
@@ 404,22 411,7 @@ audioqnotfull(void *x)
IOstate *s = x;
/* called with lock */
- return s->active.ref == 0 || s->filling != s->current;
-}
-
-static int
-audioqnotempty(IOstate *s)
-{
- /* called with lock */
- return s->next != s->filling;
-}
-
-static int
-audioidle(void *x)
-{
- IOstate *s = x;
- /* called with lock */
- return s->active.ref == 0;
+ return dmaidle(s->dma) || s->filling != s->current;
}
static void
@@ 436,50 428,46 @@ audioenable(void)
L3_init();
/* Setup the uarts */
- ppcregs->assignment &= (1<<18); /* Could be the other way round! */
+ ppcregs->assignment &= ~(1<<18);
gpioregs->altfunc &= ~(GPIO_SSP_TXD_o | GPIO_SSP_RXD_i | GPIO_SSP_SCLK_o | GPIO_SSP_SFRM_o);
gpioregs->altfunc |= (GPIO_SSP_CLK_i);
gpioregs->direction &= ~(GPIO_SSP_CLK_i);
- sspregs->control0 = 0xf<<0 | 0x1<<4 | 0x3<<8;
- sspregs->control1 = 0<<3 + 0<<4 + 1<<5;
-
- sspregs->control0 |= 1<<7; /* enable */
+ sspregs->control0 = 0;
+ sspregs->control0 = 0x031f; /* 16 bits, TI frames, serial clock rate 3 */
+ sspregs->control1 = 0x0020; /* ext clock */
+ sspregs->control0 = 0x039f; /* enable */
/* Enable the audio power */
audiopower(1);
amplifierpower(1);
audiomute(0);
+ /* external clock configured for 44100 samples/sec */
gpioregs->direction |= (GPIO_CLK_SET0_o|GPIO_CLK_SET1_o);
- /* external clock configured for 44100 samples/sec */
- gpioregs->set = GPIO_CLK_SET0_o;
- gpioregs->clear = GPIO_CLK_SET1_o;
-
+/* This is purportedly the wrong way round: 0 should be set, 1 cleared */
+ gpioregs->set = GPIO_CLK_SET0_o|GPIO_CLK_SET1_o;
+// gpioregs->clear = GPIO_CLK_SET1_o;
+
/* Wait for the UDA1341 to wake up */
delay(100);
- print("Ser4SSSR=0x%lux\n", sspregs->status);
-
- gpioregs->clear = EGPIO_codec_reset;
- gpioregs->set = EGPIO_codec_reset;
/* Reset the chip */
- data[0] = 2<<4 /* system clock */ | 1<<1 /* lsb16 */ | 1<<6 /* reset */;
+ data[0] = 2<<UdaStatusSC | 1<<UdaStatusIF | 1<<UdaStatusRST;
+ L3_write(UDA1341_L3Addr<<2 | UDA1341_STATUS, data, 1 );
+ gpioregs->set = EGPIO_codec_reset;
+ gpioregs->clear = EGPIO_codec_reset;
+ /* write uda 1341 status[0] */
+ data[0] &= ~(1<<UdaStatusRST); /* clear reset */
L3_write(UDA1341_L3Addr<<2 | UDA1341_STATUS, data, 1 );
-
- delay(10);
-
- data[0] = 2<<4 /* system clock */ | 1<<1 /* lsb16 */;
- L3_write( (UDA1341_L3Addr<<2)|UDA1341_STATUS, data, 1 );
- /* Reset done */
/* write uda 1341 status[1] */
data[0] = 0x80 | 0x3<<UdaStatusPC | 1<<UdaStatusIGS | 1<<UdaStatusOGS;
L3_write(UDA1341_L3Addr<<2 | UDA1341_STATUS, data, 1);
/* write uda 1341 data0[0] (volume) */
- data[0] = 0x00 | /* volume */ 15 & 0x3f; /* 6 bits, others must be 0 */
+ data[0] = 15 & 0x3f; /* 6 bits, others must be 0 */
L3_write(UDA1341_L3Addr<<2 | UDA1341_DATA0, data, 1);
/* write uda 1341 data0[2] (mode switch) */
@@ 501,31 489,28 @@ audioenable(void)
data[1] = 0xe0 | 0<<2 | 3; /* agc time constant and output level */
L3_write(UDA1341_L3Addr<<2 | UDA1341_DATA0, data, 2 );
- /* Reset the chip */
- data[0] = 2<<4 /* system clock */ | 1<<1 /* lsb16 */ | 1<<6 /* reset */;
- L3_write(UDA1341_L3Addr<<2 | UDA1341_STATUS, data, 1 );
-
- delay(10);
-
- data[0] = 2<<4 /* system clock */ | 1<<1 /* lsb16 */;
- L3_write( (UDA1341_L3Addr<<2)|UDA1341_STATUS, data, 1 );
- /* Reset done */
-
- if (debug) print("#A: audio enabled\n");
+ if (debug) {
+ print("#A: audio enabled\n");
+ print("\tsspregs->control0 = 0x%lux\n", sspregs->control0);
+ print("\tsspregs->control1 = 0x%lux\n", sspregs->control1);
+ }
}
static void
sendaudio(IOstate *b) {
/* interrupt routine calls this too */
+ int n;
+
if (debug > 1) print("#A: sendaudio\n");
ilock(&b->ilock);
while (b->next != b->filling) {
assert(b->next->nbytes);
- incref(&b->active);
- if (dmastart(b->dma, b->next->virt, b->next->nbytes) == 0) {
- decref(&b->active);
+ if ((n = dmastart(b->dma, b->next->virt, b->next->nbytes)) == 0) {
+ iostats.faildma++;
break;
}
+ iostats.totaldma++;
+ if (n == 1) iostats.idledma++;
if (debug > 1) print("#A: dmastart @%p\n", b->next);
b->next->nbytes = 0;
b->next++;
@@ 536,7 521,7 @@ sendaudio(IOstate *b) {
}
static void
-audiointr(void *x, ulong) {
+audiointr(void *x, ulong ndma) {
IOstate *s = x;
if (s == &audio.o) {
@@ 545,8 530,8 @@ audiointr(void *x, ulong) {
s->current++;
if (s->current == &s->buf[Nbuf])
s->current = &s->buf[0];
- decref(&s->active);
- sendaudio(s);
+ if (ndma > 0)
+ sendaudio(s);
}
wakeup(&s->vous);
}
@@ 596,6 581,7 @@ audioopen(Chan *c, int omode)
error(Einuse);
}
audioenable();
+ memset(&iostats, 0, sizeof(iostats));
if (omode & Aread) {
/* read */
audio.amode |= Aread;
@@ 663,10 649,13 @@ audioclose(Chan *c)
audio.o.filling = &audio.o.buf[0];
sendaudio(&audio.o);
}
- while(!audioidle(&audio.o))
- sleep(&audio.o.vous, audioidle, &audio.o);
+ delay(2000);
+ // dmawait(audio.o.dma);
+ if (!dmaidle(audio.o.dma))
+ print("dma still busy\n");
amplifierpower(0);
setempty(&audio.o);
+ dmafree(audio.o.dma);
}
if (audio.i.chan == c) {
/* closing the read end */
@@ 680,6 669,9 @@ audioclose(Chan *c)
poperror();
qunlock(&audio.o);
qunlock(&audio);
+ print("total dmas: %lud\n", iostats.totaldma);
+ print("dmas while idle: %lud\n", iostats.idledma);
+ print("dmas while busy: %lud\n", iostats.faildma);
}
break;
}
@@ 857,7 849,7 @@ audiowrite(Chan *c, void *vp, long n, vlong)
}
while(n > 0) {
/* wait if dma in progress */
- while (a->active.ref && a->filling == a->current) {
+ while (!dmaidle(a->dma) && a->filling == a->current) {
if (debug > 1) print("#A: sleep\n");
sleep(&a->vous, audioqnotfull, a);
}
M bitsy/io.h => bitsy/io.h +15 -0
@@ 248,3 248,18 @@ struct SSPregs {
ulong status;
};
extern SSPregs *sspregs;
+
+/* Multimedia Communications Port controller registers */
+typedef struct MCPregs MCPregs;
+struct MCPregs {
+ ulong control0;
+ ulong reserved0;
+ ulong data0;
+ ulong data1;
+ ulong data2;
+ ulong reserved1;
+ ulong status;
+ ulong reserved[11];
+ ulong control1;
+};
+extern MCPregs *mcpregs;
M bitsy/main.c => bitsy/main.c +11 -0
@@ 16,6 16,7 @@ int noprint;
static void gpioinit(void);
static void ppcinit(void);
static void sspinit(void);
+static void mcpinit(void);
void
main(void)
@@ 39,6 40,7 @@ main(void)
mmuinit();
gpioinit();
ppcinit();
+ mcpinit();
sspinit();
trapinit();
sa1100_uartsetup(1);
@@ 386,6 388,15 @@ ppcinit(void) {
ppcregs = mapspecial(PPCREGS, 32);
}
+MCPregs *mcpregs;
+
+static void
+mcpinit(void) {
+ mcpregs = mapspecial(MCPREGS, 0x34);
+ mcpregs->status &= ~(1<<16);
+ /* Turn MCP operations off */
+}
+
SSPregs *sspregs;
static void
M bitsy/sa1110dma.c => bitsy/sa1110dma.c +41 -25
@@ 41,8 41,8 @@ enum {
};
typedef struct DMAchan {
+ Lock;
int allocated;
- Ref active;
Rendez r;
void (*intr)(void*, ulong);
void *param;
@@ 116,51 116,58 @@ dmafree(int i) {
ulong
dmastart(int chan, void *addr, int count) {
- ulong status;
+ ulong status, n;
+ ilock(&dma.chan[chan]);
status = dmaregs[chan].dcsr_rd;
- if (debug > 1) print("dma: dmastart 0x%lux\n", status);
+ if (debug > 1)
+ iprint("dma: dmastart 0x%lux\n", status);
- if (dma.chan[chan].active.ref >= 2) {
- if (debug > 1) print("\n");
+ if ((status & (1<<STRTA|1<<STRTB|1<<RUN)) == (1<<STRTA|1<<STRTB|1<<RUN)) {
+ iunlock(&dma.chan[chan]);
return 0;
}
-
- if ((status & (1<<DONEA|1<<DONEB|1<<RUN)) == 1<<RUN)
- panic("dmastart called while busy");
-
cachewbregion((ulong)addr, count);
+ n = 1;
if ((status & (1<<BIU | 1<<STRTB)) == (1<<BIU | 1<<STRTB) ||
(status & (1<<BIU | 1<<STRTA)) == 0) {
- dmaregs[chan].dcsr_clr = 1<<DONEA | 1<<STRTA;
+ assert((status & 1<<STRTA) == 0);
+ if (status & 1<<RUN)
+ n = 2;
dmaregs[chan].dstrtA = addr;
dmaregs[chan].dxcntA = count-1;
- incref(&dma.chan[chan].active);
dmaregs[chan].dcsr_set = 1<<RUN | 1<<IE | 1<<STRTA;
- return 1<<DONEA;
} else {
- dmaregs[chan].dcsr_clr = 1<<DONEB | 1<<STRTB;
+ assert((status & 1<<STRTB) == 0);
+ if (status & 1<<RUN)
+ n = 2;
dmaregs[chan].dstrtB = addr;
dmaregs[chan].dxcntB = count-1;
- incref(&dma.chan[chan].active);
dmaregs[chan].dcsr_set = 1<<RUN | 1<<IE | 1<<STRTB;
- return 1<<DONEB;
}
+ iunlock(&dma.chan[chan]);
+ return n;
}
int
dmaidle(int chan) {
- return dma.chan[chan].active.ref == 0;
+ ulong status;
+
+ status = dmaregs[chan].dcsr_rd;
+ return (status & (1<<STRTA|1<<STRTB|1<<RUN)) == 0;
}
static int
_dmaidle(void* chan) {
- return dma.chan[(int)chan].active.ref == 0;
+ ulong status;
+
+ status = dmaregs[(int)chan].dcsr_rd;
+ return (status & (1<<STRTA|1<<STRTB|1<<RUN)) == 0;
}
void
dmawait(int chan) {
- while (dma.chan[chan].active.ref)
+ while (!dmaidle(chan))
sleep(&dma.chan[chan].r, _dmaidle, (void*)chan);
}
@@ 175,6 182,7 @@ dmaintr(Ureg*, void *x)
ulong dcsr, donebit;
i = regs - dmaregs;
+ ilock(&dma.chan[i]);
dcsr = regs->dcsr_rd;
if (debug > 1)
iprint("dma: interrupt channel %d, status 0x%lux\n", i, dcsr);
@@ 182,12 190,20 @@ dmaintr(Ureg*, void *x)
iprint("error, channel %d, status 0x%lux\n", i, dcsr);
donebit = 1<<((dcsr&1<<BIU)?DONEA:DONEB);
if (dcsr & donebit) {
- regs->dcsr_clr |= donebit;
- if (dma.chan[i].intr)
- (*dma.chan[i].intr)(dma.chan[i].param, 3-dma.chan[i].active.ref);
- /* must call interrupt routine before calling decref */
- decref(&dma.chan[i].active);
+ regs->dcsr_clr = donebit;
+ /* try the other bit as well */
+ donebit ^= 1<<DONEA|1<<DONEB;
+ if (dcsr & donebit) {
+ regs->dcsr_clr = donebit;
+ }
+ iunlock(&dma.chan[i]);
+ if (dma.chan[i].intr) {
+ dcsr &= 1<<STRTA | 1<<STRTB | 1<<RUN;
+ (*dma.chan[i].intr)(dma.chan[i].param, dcsr == 0);
+ }
wakeup(&dma.chan[i].r);
- } else
- iprint("spurious DMA interrupt, channel %d, status 0x%lux\n", i, dcsr);
+ return;
+ }
+ iprint("spurious DMA interrupt, channel %d, status 0x%lux\n", i, dcsr);
+ iunlock(&dma.chan[i]);
}
M pc/devi82365.c => pc/devi82365.c +42 -25
@@ 446,19 446,23 @@ pcmspecial(char *idstr, ISAConf *isa)
for(pp = slot; pp < lastslot; pp++){
if(pp->special)
continue; /* already taken */
- enabled = 0;
- /* make sure we don't power on cards when we already know what's
- * in them. We'll reread every two minutes if necessary
+
+ /*
+ * make sure we don't power on cards when we already know what's
+ * in them. We'll reread every two minutes if necessary
*/
- if (pp->msec == ~0 || TK2MS(MACHP(0)->ticks) - pp->msec > 120000) {
+ enabled = 0;
+ if (pp->msec == ~0 || TK2MS(MACHP(0)->ticks) - pp->msec > 120000){
increfp(pp);
enabled++;
}
if(pp->occupied) {
- if(strstr(pp->verstr, idstr)) {
- if (!enabled)
+ if(strstr(pp->verstr, idstr)){
+ if (!enabled){
+ enabled = 1;
increfp(pp);
+ }
if(isa == 0 || pcmio(pp->slotno, isa) == 0){
pp->special = 1;
return pp->slotno;
@@ 557,7 561,9 @@ i82365probe(int x, int d, int dev)
outb(x, Rid + (dev<<7));
id = inb(d);
if((id & 0xf0) != 0x80)
- return 0; /* not this family */
+ return 0; /* not a memory & I/O card */
+ if((id & 0x0f) == 0x00)
+ return 0; /* no revision number, not possible */
cp = xalloc(sizeof(I82365));
cp->xreg = x;
@@ 588,22 594,28 @@ i82365probe(int x, int d, int dev)
break;
}
+#ifdef adsf
+ /* if it's not a Cirrus, it could be a Vadem... */
if(cp->type == Ti82365){
+ /* unlock the Vadem extended regs */
outb(x, 0x0E + (dev<<7));
outb(x, 0x37 + (dev<<7));
+
+ /* make the id register show the Vadem id */
outb(x, 0x3A + (dev<<7));
c = inb(d);
outb(d, c|0xC0);
outb(x, Rid + (dev<<7));
c = inb(d);
- if(c != id && !(c & 0x08))
- print("#y%d: id %uX changed to %uX\n", ncontroller, id, c);
if(c & 0x08)
cp->type = Tvg46x;
+
+ /* go back to Intel compatible id */
outb(x, 0x3A + (dev<<7));
c = inb(d);
outb(d, c & ~0xC0);
}
+#endif asdf
/* low power mode */
outb(x, Rmisc2 + (dev<<7));
@@ 661,14 673,14 @@ i82365reset(void)
/* look for controllers if the ports aren't already taken */
if(ioalloc(0x3E0, 2, 0, "i82365.0") >= 0){
- i82365probe(0x3E0, 0x3E1, 0) ||
+ i82365probe(0x3E0, 0x3E1, 0);
i82365probe(0x3E0, 0x3E1, 1);
if(ncontroller == 0)
iofree(0x3E0);
}
if(ioalloc(0x3E2, 2, 0, "i82365.1") >= 0){
i = ncontroller;
- i82365probe(0x3E2, 0x3E3, 0) ||
+ i82365probe(0x3E2, 0x3E3, 0);
i82365probe(0x3E2, 0x3E3, 1);
if(ncontroller == i)
iofree(0x3E2);
@@ 690,6 702,7 @@ i82365reset(void)
pp->base = (cp->dev<<7) | (j<<6);
pp->cp = cp;
pp->msec = ~0;
+ pp->verstr[0] = 0;
slotdis(pp);
/* interrupt on status change */
@@ 813,8 826,7 @@ pcmread(int slotno, int attr, void *a, long n, vlong off)
static long
i82365read(Chan *c, void *a, long n, vlong off)
{
- char *p;
- int len;
+ char *p, *buf, *e;
Slot *pp;
ulong offset = off;
@@ 825,26 837,30 @@ i82365read(Chan *c, void *a, long n, vlong off)
case Qattr:
return pcmread(SLOTNO(c), TYPE(c) == Qattr, a, n, off);
case Qctl:
- p = malloc(READSTR);
- len = 0;
+ buf = p = malloc(READSTR);
+ e = p + READSTR;
pp = slot + SLOTNO(c);
- if(pp->occupied)
- len += snprint(p+len, READSTR-len, "occupied\n");
+ buf[0] = 0;
+ if(pp->occupied){
+ p = seprint(p, e, "occupied\n");
+ if(pp->verstr[0])
+ p = seprint(p, e, "version %s\n", pp->verstr);
+ }
if(pp->enabled)
- len += snprint(p+len, READSTR-len, "enabled\n");
+ p = seprint(p, e, "enabled\n");
if(pp->powered)
- len += snprint(p+len, READSTR-len, "powered\n");
+ p = seprint(p, e, "powered\n");
if(pp->configed)
- len += snprint(p+len, READSTR-len, "configed\n");
+ p = seprint(p, e, "configed\n");
if(pp->wrprot)
- len += snprint(p+len, READSTR-len, "write protected\n");
+ p = seprint(p, e, "write protected\n");
if(pp->busy)
- len += snprint(p+len, READSTR-len, "busy\n");
- snprint(p+len, READSTR-len, "battery lvl %d\n", pp->battery);
+ p = seprint(p, e, "busy\n");
+ seprint(p, e, "battery lvl %d\n", pp->battery);
- n = readstr(offset, a, n, p);
- free(p);
+ n = readstr(offset, a, n, buf);
+ free(buf);
return n;
}
@@ 1183,6 1199,7 @@ cisread(Slot *pp)
pp->cpresent = 0;
pp->configed = 0;
pp->nctab = 0;
+ pp->verstr[0] = 0;
for(i = 0; i < nelem(cistab); i++) {
if((nv = pcmcistuple(pp->slotno, cistab[i].n, -1, v, sizeof(v))) >= 0) {