Plan 9 from Bell Labs’s /usr/web/sources/extra/9hist/bitsy/sa1110dma.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


## diffname bitsy/sa1110dma.c 2000/1103
## diff -e /dev/null /n/emeliedump/2000/1103/sys/src/9/bitsy/sa1110dma.c
0a
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"io.h"
#include	"../port/error.h"

/*
 *	DMA helper routines
 */

enum {
	NDMA	=	6,			/* Number of DMA channels */
	DMAREGS	=	0xb0000000,	/* DMA registers, physical */
};

enum {
	/* Device Address Register, DDAR */
	RW		=	0,
	E		=	1,
	BS		=	2,
	DW		=	3,
	DS		=	4,	/* bits 4 - 7 */
	DA		=	8	/* bits 8 - 31 */
};

enum {
	/* Device Control & Status Register, DCSR */
	RUN		=	0,
	IE		=	1,
	ERROR	=	2,
	DONEA	=	3,
	STRTA	=	4,
	DONEB	=	5,
	STRTB	=	6,
	BIU		=	7
};

struct {
	Lock;
	Rendez	r;
	int		channels;
} dma;

struct dmaregs {
	ulong	ddar;
	ulong	dcsr_set;
	ulong	dcsr_clr;
	ulong	dcsr_rd;
	ulong	dstrtA;
	ulong	dxcntA;
	ulong	dstrtB;
	ulong	dxcntB;
} *dmaregs;

void
dmainit(void) {
	/* map the lcd regs into the kernel's virtual space */
	dmaregs = (struct dmaregs*)mapspecial(DMAREGS, NDMA*sizeof(struct dmaregs));;
}

int
dmaalloc(int rd, int bigendian, int burstsize, int datumsize, int device, void *port) {
	int i;

	lock(&dma);
	for (i = 0; i < NDMA; i++) {
		if (dma.channels & (1 << i))
			continue;
		dma.channels |= 1 << i;
		unlock(&dma);
		dmaregs[i].ddar =
			(rd?1:0)<<RW |
			(bigendian?1:0)<<E |
			((burstsize==8)?1:0)<<BS |
			((datumsize==2)?1:0)<<DW |
			device<<DS |
			0x80000000 | (port << 6);
		return i;
	}
	unlock(&dma);
	return -1;
}

void
dmafree(i) {
	int i;

	lock(&dma);
	dma.channels &= ~(1<<i);
	unlock(&dma);
}

static int
dmaready(void *dcsr) {

	return = *(ulong*)dcsr & ((1<<DONEA)|(1<<DONEB));
}

int
dmastart(int chan, void *addr, int count) {
	ulong ab;

	while ((ab = dmaready(&dma[chan].dcsr_rd)) == 0) {
		sleep(&dma.r, dmaready, &dma[chan].dcsr_rd);
	}
	cachewb();
	if (ab & (1<<DONEA)) {
		dma[chan].dcsr_clr |= 1<<DONEA | 1<<STARTA;
		dma[chan].dstrtA = addr;
		dma[chan].dxcntA = count-1;
		dma[chan].dcsr_set |= 1<<RUN | 1<<IE | 1<<STARTA;
	} else {
		dma[chan].dcsr_clr |= 1<<DONEB | 1<<STARTB;
		dma[chan].dstrtB = addr;
		dma[chan].dxcntB = count-1;
		dma[chan].dcsr_set |= 1<<RUN | 1<<IE | 1<<STARTB;
	}
}

/*
 *  interrupt routine
 */
static void
dmaintr(Ureg*, void *x)
{
	for (i = 0; i < NDMA; i++) {

	}
}
.
## diffname bitsy/sa1110dma.c 2000/1104
## diff -e /n/emeliedump/2000/1103/sys/src/9/bitsy/sa1110dma.c /n/emeliedump/2000/1104/sys/src/9/bitsy/sa1110dma.c
129a
	for (i = 0; i < NDMA; i++) {
		if (dmaregs[i].dcsr_rd & (1<<DONEA | 1<<DONEB | 1<<ERROR))
			wakeup(&dma.r[i]);
.
128c
	int i;
.
121a
ulong
dmadone(int chan, ulong op) {
	ulong dcsr;

	dcsr = dmaregs[chan].dcsr_rd;
	if (dcsr & 1<<ERROR)
		pprint("DMA error, chan %d, status 0x%lux\n", chan, dcsr);
	return dcsr & (op | 1<<ERROR);
}

void
dmawait(int chan, ulong op) {
	ulong dcsr;

	while (((dcsr = dmaregs[chan].dcsr_rd) & (op | 1<<ERROR)) == 0)
		sleep(&dma.r[chan], dmaready, &dmaregs[chan].dcsr_rd);
	if (dcsr & 1<<ERROR)
		pprint("DMA error, chan %d, status 0x%lux\n", chan, dcsr);
}

.
115,118c
		dmaregs[chan].dcsr_clr |= 1<<DONEB | 1<<STRTB;
		dmaregs[chan].dstrtB = addr;
		dmaregs[chan].dxcntB = count-1;
		dmaregs[chan].dcsr_set |= 1<<RUN | 1<<IE | 1<<STRTB;
		return 1<<DONEB;
.
110,113c
		dmaregs[chan].dcsr_clr |= 1<<DONEA | 1<<STRTA;
		dmaregs[chan].dstrtA = addr;
		dmaregs[chan].dxcntA = count-1;
		dmaregs[chan].dcsr_set |= 1<<RUN | 1<<IE | 1<<STRTA;
		return 1<<DONEA;
.
105,106c
	while ((ab = dmaready(&dmaregs[chan].dcsr_rd)) == 0) {
		sleep(&dma.r[chan], dmaready, &dmaregs[chan].dcsr_rd);
.
101c
ulong
.
97,98c
	return *(int*)dcsr & ((1<<DONEA)|(1<<DONEB));
.
87,89c
dmafree(int i) {
.
79c
			0x80000000 | ((ulong)port << 6);
.
53c
	void*	dstrtB;
.
51c
	void*	dstrtA;
.
42c
	Rendez	r[6];
.
## diffname bitsy/sa1110dma.c 2000/1109
## diff -e /n/emeliedump/2000/1104/sys/src/9/bitsy/sa1110dma.c /n/emeliedump/2000/1109/sys/src/9/bitsy/sa1110dma.c
150,151c
		if ((dcsr = dmaregs[i].dcsr_rd) & (1<<DONEA | 1<<DONEB | 1<<ERROR))
			wakeup(&dma.chan[i].r);
			if (dma.chan[i].f)
				(*dma.chan[i].f)(dcsr);
.
147a
	ulong dcsr;
.
136c
		sleep(&dma.chan[chan].r, dmaready, &dmaregs[chan].dcsr_rd);
.
102,106c
	if (((status = dmaregs[chan].dcsr_rd) & ((1<<DONEA)|(1<<DONEB))) == 0)
		return 0;

	cachewbregion(addr, count);
	if ((status & (1<<BIU | 1<<STRTB)) == (1<<BIU | 1<<STRTB) ||
				(status & (1<<BIU | 1<<STRTA)) == (1<<STRTA)) {
.
100c
	ulong status;
.
88,90c
	dma.chan[i].inuse = 0;
.
71c
		dma.chan[i].inuse++;
.
69c
		if (dma.chan[i].inuse)
.
42,43c
	Chan	chan[6];
.
39a
typedef struct Chan {
	int		inuse;
	Rendez	r;
	void	(*f)(void);
} Chan;

.
## diffname bitsy/sa1110dma.c 2000/1110
## diff -e /n/emeliedump/2000/1109/sys/src/9/bitsy/sa1110dma.c /n/emeliedump/2000/1110/sys/src/9/bitsy/sa1110dma.c
157,158c
			if (dma.chan[i].intr)
				(*dma.chan[i].intr)(dma.chan[i].param, dcsr);
.
134a
int
dmaidle(int chan) {
	ulong dcsr;

	dcsr = dmaregs[chan].dcsr_rd;
	if (dcsr & 1<<ERROR)
		pprint("DMA error, chan %d, status 0x%lux\n", chan, dcsr);
	return (dcsr & (1<<DONEA | 1<<DONEB)) == (1<<DONEA | 1<<DONEB);
}

.
93a
	dma.chan[i].intr = nil;
.
84a
		dma.chan[i].intr = intr;
		dma.chan[i].param = param;
.
69c
dmaalloc(int rd, int bigendian, int burstsize, int datumsize, int device, void *port, void (*intr)(int, ulong), void *param) {
.
43c
	void	(*intr)(int, ulong);
	void	*param;
.
7a
#include	"sa1110dma.h"
.
## diffname bitsy/sa1110dma.c 2000/1111
## diff -e /n/emeliedump/2000/1110/sys/src/9/bitsy/sa1110dma.c /n/emeliedump/2000/1111/sys/src/9/bitsy/sa1110dma.c
169,174c
	i = regs - dmaregs;
	if ((dcsr = regs->dcsr_rd) & (1<<DONEA | 1<<DONEB | 1<<ERROR)) {
		wakeup(&dma.chan[i].r);
		if (dma.chan[i].intr)
			(*dma.chan[i].intr)(dma.chan[i].param, dcsr);
	} else
		print("spurious DMA interrupt, channel %d, status 0x%lux\n", i, dcsr);
.
166a
	struct dmaregs *regs = x;
.
113c
	cachewbregion((ulong)addr, count);
.
71c
dmaalloc(int rd, int bigendian, int burstsize, int datumsize, int device, ulong port, void (*intr)(void*, ulong), void *param) {
.
67a
	for (i = 0; i < NDMA; i++) {
		intrenable(IRQdma0+i, dmaintr, &dmaregs[i], "DMA");
	}
.
65a
	int i;

.
63a
static void	dmaintr(Ureg*, void *);

.
50c
	DMAchan	chan[6];
.
46c
} DMAchan;
.
44c
	void	(*intr)(void*, ulong);
.
41c
typedef struct DMAchan {
.
## diffname bitsy/sa1110dma.c 2000/1113
## diff -e /n/emeliedump/2000/1111/sys/src/9/bitsy/sa1110dma.c /n/emeliedump/2000/1113/sys/src/9/bitsy/sa1110dma.c
176a
	if (debug) print("dma: interrupt\n");
.
116a
	if (debug) print("dma: dmastart\n");
.
80a
	if (debug) print("dma: dmaalloc\n");
.
9a
static int debug = 1;

.
## diffname bitsy/sa1110dma.c 2000/1115
## diff -e /n/emeliedump/2000/1113/sys/src/9/bitsy/sa1110dma.c /n/emeliedump/2000/1115/sys/src/9/bitsy/sa1110dma.c
188c
		iprint("spurious DMA interrupt, channel %d, status 0x%lux\n", i, dcsr);
.
186c
			(*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);
		wakeup(&dma.chan[i].r);
.
183,184c
	dcsr = regs->dcsr_rd;
	if (debug > 1)
		iprint("dma: interrupt channel %d, status 0x%lux\n", i, dcsr);
	if (dcsr & 1<<ERROR)
		iprint("error, channel %d, status 0x%lux\n", i, dcsr);
	donebit = 1<<((dcsr&1<<BIU)?DONEA:DONEB);
	if (dcsr & donebit) {
		regs->dcsr_clr |= donebit;
.
181d
179c
	ulong dcsr, donebit;
.
162,168c
dmawait(int chan) {
	while (dma.chan[chan].active.ref)
		sleep(&dma.chan[chan].r, _dmaidle, (void*)chan);
.
155,158c
static int
_dmaidle(void* chan) {
	return dma.chan[(int)chan].active.ref == 0;
.
153c
	return dma.chan[chan].active.ref == 0;
}
.
141,150d
136c
		incref(&dma.chan[chan].active);
		dmaregs[chan].dcsr_set = 1<<RUN | 1<<IE | 1<<STRTB;
.
133c
		dmaregs[chan].dcsr_clr = 1<<DONEB | 1<<STRTB;
.
130c
		incref(&dma.chan[chan].active);
		dmaregs[chan].dcsr_set = 1<<RUN | 1<<IE | 1<<STRTA;
.
126,127c
		(status & (1<<BIU | 1<<STRTA)) == 0) {
		dmaregs[chan].dcsr_clr = 1<<DONEA | 1<<STRTA;
.
123a
	if ((status & (1<<DONEA|1<<DONEB|1<<RUN)) == 1<<RUN)
		panic("dmastart called while busy");

.
122a
	}
.
120,121c
	status = dmaregs[chan].dcsr_rd;
	if (debug > 1) print("dma: dmastart 0x%lux\n", status);

	if (dma.chan[chan].active.ref >= 2) {
		if (debug > 1) print("\n");
.
111,115d
107c
	dma.chan[i].allocated = 0;
.
98a
		dmaregs[i].dcsr_clr = 0xff;
.
96a
		dmaregs[i].ddar = ddar;
		if (debug) print("dma: dmaalloc: 0x%lux\n", ddar);
.
90c
		ddar =
.
88c
		dma.chan[i].allocated++;
.
86c
		if (dma.chan[i].allocated)
.
83d
81a
	ulong ddar;
.
73a
	if (debug) print("dma: dmaalloc registers 0x%ux mapped at 0x%p\n",
		DMAREGS, dmaregs);
.
44c
	int		allocated;
	Ref		active;
.
## diffname bitsy/sa1110dma.c 2000/1116
## diff -e /n/emeliedump/2000/1115/sys/src/9/bitsy/sa1110dma.c /n/emeliedump/2000/1116/sys/src/9/bitsy/sa1110dma.c
191,192c
		return;
	}
	iprint("spurious DMA interrupt, channel %d, status 0x%lux\n", i, dcsr);
	iunlock(&dma.chan[i]);
.
185,189c
		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);
		}
.
177a
	ilock(&dma.chan[i]);
.
163c
	while (!dmaidle(chan))
.
158c
	ulong status;

	status = dmaregs[(int)chan].dcsr_rd;
	return (status & (1<<STRTA|1<<STRTB|1<<RUN)) == 0;
.
153c
	ulong status;

	status = dmaregs[chan].dcsr_rd;
	return (status & (1<<STRTA|1<<STRTB|1<<RUN)) == 0;
.
148a
	iunlock(&dma.chan[chan]);
	return n;
.
147d
145d
142c
		assert((status & 1<<STRTB) == 0);
		if (status & 1<<RUN)
			n = 2;
.
140d
138d
135c
		assert((status & 1<<STRTA) == 0);
		if (status & 1<<RUN)
			n = 2;
.
132a
	n = 1;
.
128,131d
124,125c
	if ((status & (1<<STRTA|1<<STRTB|1<<RUN)) == (1<<STRTA|1<<STRTB|1<<RUN)) {
		iunlock(&dma.chan[chan]);
.
122c
	if (debug > 1)
		iprint("dma: dmastart 0x%lux\n", status);
.
120a
	ilock(&dma.chan[chan]);
.
119c
	ulong status, n;
.
45d
43a
	Lock;
.
## diffname bitsy/sa1110dma.c 2000/1117
## diff -e /n/emeliedump/2000/1116/sys/src/9/bitsy/sa1110dma.c /n/emeliedump/2000/1117/sys/src/9/bitsy/sa1110dma.c
208d
201,202c
			(*dma.chan[i].intr)(dma.chan[i].param, dcsr & (1<<DONEA|1<<DONEB));
.
194,199d
185d
165c
	return (status & (1<<STRTA|1<<STRTB)) == 0;
.
157c
	if (debug > 1) print("dmaidle: 0x%lux\n", status);
	return (status & (1<<STRTA|1<<STRTB)) == 0;
.
148d
141,143c
		if (status & 1<<STRTB)
			iprint("writing busy dma entry 0x%lux\n", status);
		if (status & 1<<STRTA)
			n = (last == 2)?2:3;
		last = 1;
.
134,136c
		if (status & 1<<STRTA)
			iprint("writing busy dma entry 0x%lux\n", status);
		if (status & 1<<STRTB)
			n = (last == 1)?2:3;
		last = 2;
.
127d
121c
	/* If this gets called from interrupt routines, make sure ilocks are used */
.
119a
	static int last;
.
112a
	dmaregs[i].dcsr_clr = 0xff;
	dmaregs[i].ddar = 0;
.
74c
	dmaregs = (struct dmaregs*)mapspecial(DMAREGS, NDMA*sizeof(struct dmaregs));
.
44d
## diffname bitsy/sa1110dma.c 2000/1118
## diff -e /n/emeliedump/2000/1117/sys/src/9/bitsy/sa1110dma.c /n/emeliedump/2000/1118/sys/src/9/bitsy/sa1110dma.c
131c
	cachewbregion(addr, count);
.
119c
dmastart(int chan,  ulong addr, int count) {
.
62c
	ulong	dstrtB;
.
60c
	ulong	dstrtA;
.
## diffname bitsy/sa1110dma.c 2000/1120
## diff -e /n/emeliedump/2000/1118/sys/src/9/bitsy/sa1110dma.c /n/emeliedump/2000/1120/sys/src/9/bitsy/sa1110dma.c
150c
		dmaregs[chan].dxcntB = count;
.
141c
		dmaregs[chan].dxcntA = count;
.
10c
static int debug = 0;
.
## diffname bitsy/sa1110dma.c 2000/1122
## diff -e /n/emeliedump/2000/1120/sys/src/9/bitsy/sa1110dma.c /n/emeliedump/2000/1122/sys/src/9/bitsy/sa1110dma.c
199a
		}
		wakeup(&dma.chan[i].r);
		return;
	}
	if (dcsr & 1<<ERROR) {
		regs->dcsr_clr = ERROR;
		iprint("DMA error, channel %d, status 0x%lux\n", i, dcsr);
		if (dma.chan[i].intr) {
			(*dma.chan[i].intr)(dma.chan[i].param, 0);
.
197c
		regs->dcsr_clr = 1<<DONEA|1<<DONEB;
.
117a
void
dmastop(int i) {
	dmaregs[i].dcsr_clr = 0xff;
}

.
## diffname bitsy/sa1110dma.c 2000/1125
## diff -e /n/emeliedump/2000/1122/sys/src/9/bitsy/sa1110dma.c /n/emeliedump/2000/1125/sys/src/9/bitsy/sa1110dma.c
103d
92,100c
		dmareset(i, rd, bigendian, burstsize, datumsize, device, port);
.
84d
80a
void
dmareset(int i, int rd, int bigendian, int burstsize, int datumsize, int device, ulong port) {
	ulong ddar;

	ddar =
		(rd?1:0)<<RW |
		(bigendian?1:0)<<E |
		((burstsize==8)?1:0)<<BS |
		((datumsize==2)?1:0)<<DW |
		device<<DS |
		0x80000000 | ((ulong)port << 6);
	dmaregs[i].ddar = ddar;
	dmaregs[i].dcsr_clr = 0xff;
	if (debug) print("dma: dmareset: 0x%lux\n", ddar);
}

.
## diffname bitsy/sa1110dma.c 2000/1205
## diff -e /n/emeliedump/2000/1125/sys/src/9/bitsy/sa1110dma.c /n/emeliedump/2000/1205/sys/src/9/bitsy/sa1110dma.c
77c
		intrenable(IRQ, IRQdma0+i, dmaintr, &dmaregs[i], "DMA");
.
## diffname bitsy/sa1110dma.c 2001/0501
## diff -e /n/emeliedump/2000/1205/sys/src/9/bitsy/sa1110dma.c /n/emeliedump/2001/0501/sys/src/9/bitsy/sa1110dma.c
10c
static int debug = 2;
.
## diffname bitsy/sa1110dma.c 2001/0502
## diff -e /n/emeliedump/2001/0501/sys/src/9/bitsy/sa1110dma.c /n/emeliedump/2001/0502/sys/src/9/bitsy/sa1110dma.c
162a
		n |= 1<<DONEB;
.
158c
			n = (last == 2)?0x200:0x300;
.
153a
		n |= 1<<DONEA;
.
149c
			n = (last == 1)?0x200:0x300;
.
143c
	n = 0x100;
.
10c
static int debug = 0;
.

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].