## diffname mpc/spi.c 2000/0516
## diff -e /dev/null /n/emeliedump/2000/0516/sys/src/9/mpc/spi.c
0a
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
typedef struct SPIparam SPIparam;
struct SPIparam {
ushort rbase;
ushort tbase;
uchar rfcr;
uchar tfcr;
ushort mrblr;
ulong rstate;
ulong rptr;
ushort rbptr;
ushort rcnt;
ulong rtmp;
ulong tstate;
ulong tptr;
ushort tbptr;
ushort tcnt;
ulong ttmp;
};
enum {
Nrdre = 2, /* receive descriptor ring entries */
Ntdre = 2, /* transmit descriptor ring entries */
Rbsize = 8, /* ring buffer size (+3 for PID+CRC16) */
Bufsize = (Rbsize+7)&~7, /* aligned */
};
enum {
/* spi-specific BD flags */
BDContin= 1<<9, /* continuous mode */
BDrxov= 1<<1, /* overrun */
BDtxun= 1<<1, /* underflow */
BDme= 1<<0, /* multimaster error */
BDrxerr= BDrxov|BDme,
BDtxerr= BDtxun|BDme,
/* spmod */
MLoop= 1<<14, /* loopback mode */
MClockInv= 1<<13, /* inactive state of SPICLK is high */
MClockPhs= 1<<12, /* SPCLK starts toggling at beginning of transfer */
MDiv16= 1<<11, /* use BRGCLK/16 as input to SPI baud rate */
MRev= 1<<10, /* normal operation */
MMaster= 1<<9,
MSlave= 0<<9,
MEnable= 1<<8,
/* LEN, PS fields */
/* spie */
MME = 1<<5,
TXE = 1<<4,
RES = 1<<3,
BSY = 1<<2,
TXB = 1<<1,
RXB = 1<<0,
};
/*
* software structures
*/
typedef struct Ctlr Ctlr;
struct Ctlr {
QLock;
int init;
SPI* spi;
SPIparam* sp;
int rxintr;
Rendez ir;
Ring;
};
static Ctlr spictlr[1];
static void interrupt(Ureg*, void*);
/*
* test driver for SPI, host mode
*/
void
spireset(void)
{
IMM *io;
SPI *spi;
SPIparam *sp;
Ctlr *ctlr;
io = m->iomem;
sp = (SPIparam*)cpmparam(SPIP, sizeof(*sp));
memset(sp, 0, sizeof(*sp));
if(sp == nil){
print("SPI: can't allocate new parameter memory\n");
return;
}
spi = (SPI*)((ulong)m->iomem+0xAA0);
ctlr = spictlr;
/* step 1: select port pins */
io->pbdir |= IBIT(30)|IBIT(29)|IBIT(28);
io->pbpar |= IBIT(30)|IBIT(29)|IBIT(28); /* SPICLK, SPIMOSI, SPIMISO */
/* step 2: set CS pin - also disables SPISEL */
io->pbpar &= ~(IBIT(31));
io->pbdir |= IBIT(31);
io->pbodr &= ~(IBIT(31));
io->pbdat &= ~(IBIT(31));
ctlr->spi = spi;
ctlr->sp = sp;
if(ioringinit(ctlr, Nrdre, Ntdre, Bufsize)<0)
panic("spireset: ioringinit");
/* step 3: configure rbase and tbase */
sp->rbase = PADDR(ctlr->rdr);
sp->tbase = PADDR(ctlr->tdr);
/* step 4: do not issue InitRxTx command - due to microcode bug */
/* step 5: */
io->sdcr = 1;
/* step 6: */
sp->rfcr = 0x10;
sp->tfcr = 0x10;
/* step 7: */
sp->mrblr = Bufsize;
/* step 7.5: init other params because of bug in microcode */
sp->rstate = 0;
sp->rbptr = sp->rbase;
sp->rcnt = 0;
sp->tstate = 0;
sp->tbptr = sp->tbase;
sp->tcnt = 0;
/* step 8-9: done by ioringinit */
/* step 10: clear events */
spi->spie = ~0;
/* step 11-12: enable interrupts */
intrenable(VectorCPIC+0x05, interrupt, spictlr, BUSUNKNOWN);
spi->spim = ~0;
/* step 13: enable in master mode, 8 bit chacters, slow clock */
spi->spmode = MMaster|MRev|MDiv16|MEnable|(0x7<<4)|0xf;
print("spi->spmode = %ux\n", spi->spmode);
}
static void
interrupt(Ureg*, void *arg)
{
int events;
Ctlr *ctlr;
SPI *spi;
ctlr = arg;
spi = ctlr->spi;
events = spi->spie;
spi->spie = events;
print("SPI#%x\n", events);
}
void
spdump(SPIparam *sp)
{
print("rbase = %ux\n", sp->rbase);
print("tbase = %ux\n", sp->tbase);
print("rfcr = %ux\n", sp->rfcr);
print("tfcr = %ux\n", sp->tfcr);
print("mrblr = %ux\n", sp->mrblr);
print("rstate = %lux\n", sp->rstate);
print("rptr = %lux\n", sp->rptr);
print("rbptr = %ux\n", sp->rbptr);
print("rcnt = %ux\n", sp->rcnt);
print("rtmp = %ux\n", sp->rtmp);
print("tstate = %lux\n", sp->tstate);
print("tptr = %lux\n", sp->tptr);
print("tbptr = %ux\n", sp->tbptr);
print("tcnt = %ux\n", sp->tcnt);
print("ttmp = %ux\n", sp->ttmp);
}
void
spitest(void)
{
BD *dre;
Block *b;
int len;
Ctlr *ctlr;
ulong status;
ctlr = spictlr;
dre = &ctlr->tdr[ctlr->tdrh];
if(dre->status & BDReady)
panic("spitest: txstart");
print("dre->status %ux %ux\n", dre[0].status, dre[1].status);
b = allocb(4);
b->wp[0] = 0xc0;
b->wp[1] = 0x00;
b->wp[2] = 0x00;
b->wp[3] = 0x00;
b->wp += 4;
len = BLEN(b);
print("len = %d\n", len);
dcflush(b->rp, len);
if(ctlr->txb[ctlr->tdrh] != nil)
panic("scc/ether: txstart");
ctlr->txb[ctlr->tdrh] = b;
dre->addr = PADDR(b->rp);
print("addr = %lux\n", PADDR(b->rp));
dre->length = len;
dre->status = (dre->status & BDWrap) | BDReady|BDInt|BDLast;
eieio();
spdump(ctlr->sp);
m->iomem->pbdat |= IBIT(31);
microdelay(1);
ctlr->spi->spcom = 1<<7; /* transmit now */
print("cpcom = %ux\n", &ctlr->spi->spcom);
spdump(ctlr->sp);
eieio();
ctlr->ntq++;
ctlr->tdrh = NEXT(ctlr->tdrh, Ntdre);
print("going into loop %ux %ux\n", dre->status, ctlr->spi->spcom);
while(dre->status&BDReady) {
print("ctrl->spi->spim = %ux %ux\n", ctlr->spi->spie, dre->status);
spdump(ctlr->sp);
delay(10000);
}
delay(100);
dre = &ctlr->rdr[ctlr->rdrx];
status = dre->status;
len = dre->length;
print("%d status = %ux len=%d\n", ctlr->rdrx, status, len);
b = iallocb(len);
memmove(b->wp, KADDR(dre->addr), len);
b->wp += len;
print("%ux %ux %ux %ux\n", b->rp[0], b->rp[1], b->rp[2], b->rp[3]);
dcflush(KADDR(dre->addr), len);
dre->status = (status & BDWrap) | BDEmpty | BDInt;
ctlr->rdrx = NEXT(ctlr->rdrx, Nrdre);
m->iomem->pbdat &= ~(IBIT(31));
microdelay(1);
}
void
spiinit(void)
{
spireset();
spitest();
}
#ifdef XXX
static void
epprod(Ctlr *ctlr, int epn)
{
ctlr->spi->uscom = FifoFill | (epn&3);
eieio();
}
static void
txstart(Endpt *r)
{
int len, flags;
Block *b;
BD *dre, *rdy;
if(r->ctlr->init)
return;
rdy = nil;
while(r->ntq < Ntdre-1){
b = qget(r->oq);
if(b == 0)
break;
dre = &r->tdr[r->tdrh];
if(dre->status & BDReady)
panic("txstart");
dumpspi(b, "TX");
/*
* Give ownership of the descriptor to the chip, increment the
* software ring descriptor pointer and tell the chip to poll.
*/
flags = 0;
switch(b->rp[0]){
case TokDATA1:
flags = BDData1|BDData0;
case TokDATA0:
flags |= BDtxcrc|BDcnf|BDReady;
flags |= BDData0;
b->rp++; /* skip DATAn */
}
len = BLEN(b);
dcflush(b->rp, len);
if(r->txb[r->tdrh] != nil)
panic("spi: txstart");
r->txb[r->tdrh] = b;
dre->addr = PADDR(b->rp);
dre->length = len;
eieio();
dre->status = (dre->status & BDWrap) | BDInt|BDLast | flags;
if(rdy){
rdy->status |= BDReady;
rdy = nil;
}
if((flags & BDReady) == 0)
rdy = dre;
eieio();
r->ntq++;
r->tdrh = NEXT(r->tdrh, Ntdre);
}
if(rdy)
rdy->status |= BDReady;
eieio();
}
static void
transmit(Endpt *r)
{
ilock(r->ctlr);
txstart(r);
iunlock(r->ctlr);
}
static void
endptintr(Endpt *r, int events)
{
int len, status;
BD *dre;
Block *b;
if(events & Frxb || 1){
dre = &r->rdr[r->rdrx];
while(((status = dre->status) & BDEmpty) == 0){
if(status & BDrxerr || (status & (BDFirst|BDLast)) != (BDFirst|BDLast)){
print("spi rx: %4.4ux %d ", status, dre->length);
{uchar *p;int i; p=KADDR(dre->addr); for(i=0;i<14&&i<dre->length; i++)print(" %.2ux", p[i]);print("\n");}
}
else{
/*
* We have a packet. Read it into the next
* free ring buffer, if any.
*/
len = dre->length-2; /* discard CRC */
if(len >= 0 && (b = iallocb(len)) != 0){
memmove(b->wp, KADDR(dre->addr), len);
dcflush(KADDR(dre->addr), len);
b->wp += len;
// spiiq(ctlr, b);
dumpspi(b, "RX");
freeb(b);
}
}
/*
* Finished with this descriptor, reinitialise it,
* give it back to the chip, then on to the next...
*/
dre->length = 0;
dre->status = (dre->status & BDWrap) | BDEmpty | BDInt;
eieio();
r->rdrx = NEXT(r->rdrx, Nrdre);
dre = &r->rdr[r->rdrx];
r->rxintr = 1;
wakeup(&r->ir);
}
}
/*
* Transmitter interrupt: handle anything queued for a free descriptor.
*/
if(events & (Ftxb|Ftxe0|Ftxe1)){
lock(r->ctlr);
while(r->ntq){
dre = &r->tdr[r->tdri];
if(dre->status & BDReady)
break;
print("spitx=#%.4x %8.8lux\n", dre->status, dre->addr);
/* TO DO: error counting */
b = r->txb[r->tdri];
if(b == nil)
panic("spi/interrupt: bufp");
r->txb[r->tdri] = nil;
freeb(b);
r->ntq--;
r->tdri = NEXT(r->tdri, Ntdre);
}
txstart(r);
unlock(r->ctlr);
if(r->ntq)
epprod(r->ctlr, r->x);
}
}
static void
dumpspi(Block *b, char *msg)
{
int i;
print("%s: %8.8lux [%d]: ", msg, (ulong)b->rp, BLEN(b));
for(i=0; i<BLEN(b) && i < 16; i++)
print(" %.2x", b->rp[i]);
print("\n");
}
static void
setaddr(Endpt *e, int dev, int endpt)
{
ushort v;
e->dev = dev;
e->endpt = endpt;
v = (e->endpt<<7) | e->dev;
v |= crc5(v) << 11;
e->addr[0] = v;
e->addr[1] = v>>8;
}
static int
spiinput(void *a)
{
return ((Ctlr*)a)->rxintr;
}
static void
spitest(void)
{
Ctlr *ctlr;
Endpt *e, *e1;
uchar msg[8];
int epn, testing, i;
ctlr = spictlr;
epn = 0;
testing = ctlr->spi->usmod & TEST;
if(testing)
epn = 1;
e = &ctlr->pts[0];
e1 = &ctlr->pts[1];
memset(msg, 0, 8);
msg[0] = 0;
msg[1] = 8; /* set configuration */
msg[2] = 1;
setaddr(e, 0, epn);
sendtoken(e, TokSETUP);
senddata(e, msg, 8);
if(!testing){
for(i=0; i<8; i++)
msg[i] = 0x40+i;
senddata(e1, msg, 8);
e->rxintr = 0;
sendtoken(e, TokIN);
transmit(e);
epprod(ctlr, 0);
tsleep(&e->ir, spiinput, e, 1000);
if(!spiinput(e))
print("RX: none\n");
}
sendtoken(e, TokSETUP);
msg[0] = 0x23;
msg[1] = 3; /* set feature */
msg[2] = 8; /* port power */
msg[3] = 0;
msg[4] = 1; /* port 1 */
senddata(e, msg, 8);
if(!testing){
for(i=0; i<8; i++)
msg[i] = 0x60+i;
senddata(e1, msg, 8);
e->rxintr = 0;
sendtoken(e, TokIN);
transmit(e);
epprod(ctlr, 0);
tsleep(&e->ir, spiinput, e, 1000);
if(!spiinput(e))
print("RX: none\n");
}
}
static void
setupep(int n, EPparam *ep)
{
Endpt *e;
e = &usbctlr->pts[n];
e->x = n;
e->ctlr = usbctlr;
e->xtog = TokDATA0;
if(e->oq == nil)
e->oq = qopen(8*1024, 1, 0, 0);
if(e->iq == nil)
e->iq = qopen(8*1024, 1, 0, 0);
e->ep = ep;
if(ioringinit(e, Nrdre, Ntdre, Bufsize) < 0)
panic("usbreset");
ep->rbase = PADDR(e->rdr);
ep->rbptr = ep->rbase;
ep->tbase = PADDR(e->tdr);
ep->tbptr = ep->tbase;
eieio();
}
#endif
.
## diffname mpc/spi.c 2000/0521
## diff -e /n/emeliedump/2000/0516/sys/src/9/mpc/spi.c /n/emeliedump/2000/0521/sys/src/9/mpc/spi.c
246c
print("%d status = %lux len=%d\n", ctlr->rdrx, status, len);
.
231c
print("cpcom = %p\n", &ctlr->spi->spcom);
.
191c
print("ttmp = %lux\n", sp->ttmp);
.
186c
print("rtmp = %lux\n", sp->rtmp);
.
## diffname mpc/spi.c 2000/0817
## diff -e /n/emeliedump/2000/0521/sys/src/9/mpc/spi.c /n/emeliedump/2000/0817/sys/src/9/mpc/spi.c
521c
dre = &ctlr->tdr[ctlr->tdrh];
spicmdsend(b,dre,ctlr,1);
dre=&ctlr->rdr[ctlr->rdrx];
len=dre->length;
dcflush(KADDR(dre->addr),len);
dre->status=(dre->status&BDWrap)|BDEmpty|BDInt;
ctlr->rdrx=NEXT(ctlr->rdrx,Nrdre);
freeb(b);
delay(15);
return;
}
.
519a
b = allocb(2);
b->wp[0] = 0x07;
b->wp[1] = 0x80;
b->wp+=2;
.
502,518c
ctlr = spictlr;
.
500c
BD *dre;
Block *b;
Ctlr *ctlr;
int len;
.
497,498c
void
spieraseall(void)
.
451,494c
b = allocb(2);
b->wp[0] = 0x07;
b->wp[1] = addr&0x7f;
b->wp+=2;
dre = &ctlr->tdr[ctlr->tdrh];
spicmdsend(b,dre,ctlr,1);
dre=&ctlr->rdr[ctlr->rdrx];
len=dre->length;
dcflush(KADDR(dre->addr),len);
dre->status=(dre->status&BDWrap)|BDEmpty|BDInt;
ctlr->rdrx=NEXT(ctlr->rdrx,Nrdre);
freeb(b);
delay(15);
return;
.
446,448c
int len;
.
444a
BD *dre;
Block *b;
.
442,443c
void
spierase(ulong addr)
.
439c
BD *dre;
Block *b;
Ctlr *ctlr;
int len;
ctlr = spictlr;
dre = &ctlr->tdr[ctlr->tdrh];
b = allocb(4);
b->wp[0] = 0x04;
b->wp[1] = 0x40;
b->wp+=2;
memmove((uchar*)b->wp,buf,2);
//b->wp[2]=0xf0;
//b->wp[3]=0xf0;
b->wp += 2;
spicmdsend(b,dre,ctlr,1);
dre=&ctlr->rdr[ctlr->rdrx];
len=dre->length;
dcflush(KADDR(dre->addr),len);
dre->status=(dre->status&BDWrap)|BDEmpty|BDInt;
ctlr->rdrx=NEXT(ctlr->rdrx,Nrdre);
freeb(b);
delay(15);
//sleep(15000); //sleep for 15ms
print("leave spiwriteall\n");
return;
.
436,437c
void
spiwriteall(uchar *buf)
.
428,433c
dre = &ctlr->tdr[ctlr->tdrh];
b = allocb(4);
b->wp[0] = 0x05 ;
b->wp[1] = 0x7f & addr;
b->wp+=2;
memmove((uchar*)b->wp,buf,2);
b->wp += 2;
spicmdsend(b,dre,ctlr,1);
dre=&ctlr->rdr[ctlr->rdrx];
len=dre->length;
dcflush(KADDR(dre->addr),len);
dre->status=(dre->status&BDWrap)|BDEmpty|BDInt;
ctlr->rdrx=NEXT(ctlr->rdrx,Nrdre);
freeb(b);
delay(15);
//sleep(15); //sleep for 15ms
return;
.
426c
BD *dre;
Block *b;
Ctlr *ctlr;
int len;
ctlr = spictlr;
.
423,424c
void
spiwrite(ulong addr, uchar *buf)
.
417,420c
ctlr = spictlr;
dre = &ctlr->tdr[ctlr->tdrh];
b = allocb(4);
b->wp[0] = 0x80;
b->wp[1] = 0x00;
b->wp[2] = 0x00;
b->wp[3] = 0x00;
b->wp += 4;
spicmdsend(b,dre,ctlr,1);
dre=&ctlr->rdr[ctlr->rdrx];
len=dre->length;
dcflush(KADDR(dre->addr),len);
dre->status=(dre->status&BDWrap)|BDEmpty|BDInt;
ctlr->rdrx=NEXT(ctlr->rdrx,Nrdre);
freeb(b);
microdelay(5);
return;
.
415c
BD *dre;
Block *b;
Ctlr *ctlr;
int len;
.
411,413c
void
spidiswrite(void)
.
385,408c
dre=&ctlr->rdr[ctlr->rdrx];
len=dre->length;
dcflush(KADDR(dre->addr),len);
dre->status=(dre->status&BDWrap)|BDEmpty|BDInt;
ctlr->rdrx=NEXT(ctlr->rdrx,Nrdre);
freeb(b);
microdelay(5);
return;
.
378,383c
dre = &ctlr->tdr[ctlr->tdrh];
spicmdsend(b,dre,ctlr,1);
.
370,376c
b = allocb(4);
b->wp[0] = 0x98;
b->wp[1] = 0x00;
b->wp[2] = 0x00;
b->wp[3] = 0x00;
b->wp += 4;
.
347,368c
ctlr = spictlr;
.
345a
Ctlr *ctlr;
int len;
.
343,344c
BD *dre;
.
340,341c
void
spienwrite(void)
.
332,337c
b = iallocb(len);
memmove(b->wp, KADDR(dre->addr), len);
b->wp += len;
/* get the data out of the receiving block
the data begins at the 13th bit, and ends at the (13+16)th bit
*/
buf[0]=b->rp[1]<<4 | b->rp[2]>>4;
buf[1]=b->rp[2]<<4 | b->rp[3]>>4;
// print("read out %ux %ux\n", buf[0],buf[1]);
dcflush(KADDR(dre->addr), len);
dre->status = (status & BDWrap) | BDEmpty | BDInt;
ctlr->rdrx = NEXT(ctlr->rdrx, Nrdre);
freeb(b);
m->iomem->pbdat &= ~(IBIT(31));
microdelay(5);
return;
.
295,330c
dre = &ctlr->rdr[ctlr->rdrx];
status = dre->status;
len = dre->length;
while(dre->status&BDEmpty) microdelay(10);
.
290,293c
b = allocb(4);
b->wp[0] = 0xc0 | addr>>3;
b->wp[1] = addr<<5;
b->wp[2] = 0x00;
b->wp[3] = 0x00;
b->wp += 4;
spicmdsend(b, dre, ctlr, 0);
//delay(10);
.
282,288c
dre = &ctlr->tdr[ctlr->tdrh];
.
280c
int len;
Ctlr *ctlr;
ushort status;
ctlr = spictlr;
.
278c
BD *dre;
.
275,276c
void
spiread(ulong addr,uchar * buf)
.
268,272c
if(dre->status & BDReady)
panic("spicmdsend: txstart");
len = BLEN(b);
dcflush(b->rp, len);
ctlr->txb[ctlr->tdrh] = b;
dre->addr = PADDR(b->rp);
dre->length = len;
dre->status = (dre->status & BDWrap) | BDReady|BDInt|BDLast;
m->iomem->pbdat |= IBIT(31);
ctlr->spi->spcom = 1<<7; /* transmit now */
//eieio();
ctlr->ntq++;
ctlr->tdrh = NEXT(ctlr->tdrh, Ntdre);
delay(1);
while(dre->status&BDReady) microdelay(10);
if(CSdown) m->iomem->pbdat &= ~(IBIT(31));
.
266c
void
spicmdsend(Block *b, BD *dre, Ctlr *ctlr, int CSdown)
{
int len;
.
263c
// spitest();
.
250a
/* get the data out of the receiving block
the data begins at the 13th bit, and ends at the (13+16)th bit
*/
buf[0]=b->rp[1]<<4 | b->rp[2]>>4;
buf[1]=b->rp[2]<<4 | b->rp[3]>>4;
print("the value of address 0 in EEPROM is %ux %ux\n",buf[0],buf[1]);
.
226d
201a
uchar buf[2];
.
171c
// print("SPI#%x\n", events);
.
157c
.
## diffname mpc/spi.c 2001/0527 # deleted
## diff -e /n/emeliedump/2000/0817/sys/src/9/mpc/spi.c /n/emeliedump/2001/0527/sys/src/9/mpc/spi.c
1,547d
|