Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/*
2
 * omap3530 system dma controller
3
 *
4
 * terminology: a block consist of frame(s), a frame consist of elements
5
 * (uchar, ushort, or ulong sized).
6
 */
7
#include "u.h"
8
#include "../port/lib.h"
9
#include "mem.h"
10
#include "dat.h"
11
#include "fns.h"
12
#include "io.h"
13
#include "../port/error.h"
14
#include "../port/netif.h"
15
 
16
enum {
17
	Nirq	= 4,
18
	Baseirq	= 12,
19
 
20
	Nchan	= 32,
21
};
22
 
23
/*
24
 * has a sw reset bit
25
 * dma req lines 1, 2, 6, 63 are available for `system expansion'
26
 */
27
 
28
typedef struct Regs Regs;
29
typedef struct Dchan Dchan;
30
struct Regs {
31
	uchar	_pad0[8];
32
	/* bitfield of intrs pending, by Dchan; write 1s to clear */
33
	ulong	irqsts[Nirq];
34
	ulong	irqen[Nirq];	/* bitfield of intrs enabled, by Dchan */
35
	ulong	syssts;		/* 1<<0 is Resetdone */
36
	ulong	syscfg;		/* 1<<1 is Softreset */
37
	uchar	_pad1[0x64 - 0x30];
38
 
39
	ulong	caps[5];	/* caps[1] not defined */
40
	ulong	gcr;		/* knobs */
41
	ulong	_pad2;
42
 
43
	struct Dchan {
44
		ulong	ccr;	/* chan ctrl: incr, etc. */
45
		ulong	clnkctrl; /* link ctrl */
46
		ulong	cicr;	/* intr ctrl */
47
		ulong	csr;	/* status */
48
		ulong	csdp;	/* src & dest params */
49
		ulong	cen;	/* element # */
50
		ulong	cfn;	/* frame # */
51
		ulong	cssa;	/* src start addr */
52
		ulong	cdsa;	/* dest start addr */
53
		ulong	csei;	/* src element index */
54
		ulong	csfi;	/* src frame index | pkt size */
55
		ulong	cdei;	/* dest element index */
56
		ulong	cdfi;	/* dest frame index | pkt size */
57
		ulong	csac;	/* src addr value (read-only?) */
58
		ulong	cdac;	/* dest addr value */
59
		ulong	ccen;	/* curr transferred element # (in frame) */
60
		ulong	ccfn;	/* curr transferred frame # (in xfer) */
61
		ulong	color;
62
		uchar	_pad3[24];
63
	} chan[Nchan];
64
};
65
 
66
enum {
67
	/* cicr/csr bits */
68
	Blocki	= 1 << 5,
69
 
70
	/* ccr bits */
71
	Enable	= 1 << 7,
72
};
73
 
74
typedef struct Xfer Xfer;
75
static struct Xfer {
76
	Rendez	*rend;
77
	int	*done;		/* flag to set on intr */
78
} xfer[Nirq];
79
 
80
int
81
isdmadone(int irq)
82
{
83
	Dchan *cp;
84
	Regs *regs = (Regs *)PHYSSDMA;
85
 
86
	cp = regs->chan + irq;
87
	return cp->csr & Blocki;
88
}
89
 
90
static void
91
dmaintr(Ureg *, void *a)
92
{
93
	int i = (int)a;			/* dma request & chan # */
94
	Dchan *cp;
95
	Regs *regs = (Regs *)PHYSSDMA;
96
 
97
	assert(i >= 0 && i < Nirq);
98
 
99
	*xfer[i].done = 1;
100
	assert(xfer[i].rend != nil);
101
	wakeup(xfer[i].rend);
102
 
103
	cp = regs->chan + i;
104
	if(!(cp->csr & Blocki))
105
		iprint("dmaintr: req %d: Blocki not set; csr %#lux\n",
106
			i, cp->csr);
107
	cp->csr |= cp->csr;			/* extinguish intr source */
108
	coherence();
109
	regs->irqsts[i] = regs->irqsts[i];	/* extinguish intr source */
110
	coherence();
111
	regs->irqen[i] &= ~(1 << i);
112
	coherence();
113
 
114
	xfer[i].rend = nil;
115
	coherence();
116
}
117
 
118
void
119
zerowds(ulong *wdp, int cnt)
120
{
121
	while (cnt-- > 0)
122
		*wdp++ = 0;
123
}
124
 
125
static int
126
istestdmadone(void *arg)
127
{
128
	return *(int *)arg;
129
}
130
 
131
void
132
dmainit(void)
133
{
134
	int n;
135
	char name[16];
136
	Dchan *cp;
137
	Regs *regs = (Regs *)PHYSSDMA;
138
 
139
	if (probeaddr((uintptr)&regs->syssts) < 0)
140
		panic("dmainit: no syssts reg");
141
	regs->syssts = 0;
142
	coherence();
143
	regs->syscfg |= 1<<1;		/* Softreset */
144
	coherence();
145
	while(!(regs->syssts & (1<<0)))	/* Resetdone? */
146
		;
147
 
148
	for (n = 0; n < Nchan; n++) {
149
		cp = regs->chan + n;
150
		cp->ccr = 0;
151
		cp->clnkctrl = 0;
152
		cp->cicr = 0;
153
		cp->csr = 0;
154
		cp->csdp = 0;
155
		cp->cen = cp->cfn = 0;
156
		cp->cssa = cp->cdsa = 0;
157
		cp->csei = cp->csfi = 0;
158
		cp->cdei = cp->cdfi = 0;
159
//		cp->csac = cp->cdac = 0;		// ro
160
		cp->ccen = cp->ccfn = 0;
161
		cp->color = 0;
162
	}
163
	zerowds((void *)regs->irqsts, sizeof regs->irqsts / sizeof(ulong));
164
	zerowds((void *)regs->irqen,  sizeof regs->irqen / sizeof(ulong));
165
	coherence();
166
 
167
	regs->gcr = 65;			/* burst size + 1 */
168
	coherence();
169
 
170
	for (n = 0; n < Nirq; n++) {
171
		snprint(name, sizeof name, "dma%d", n);
172
		intrenable(Baseirq + n, dmaintr, (void *)n, nil, name);
173
	}
174
}
175
 
176
enum {
177
	Testbyte	= 0252,
178
	Testsize	= 256,
179
	Scratch		= MB,
180
};
181
 
182
/*
183
 * try to confirm sane operation
184
 */
185
void
186
dmatest(void)
187
{
188
	int n, done;
189
	uchar *bp;
190
	static ulong pat = 0x87654321;
191
	static Rendez trendez;
192
 
193
	if (up == nil)
194
		panic("dmatest: up not set yet");
195
	bp = (uchar *)KADDR(PHYSDRAM + 128*MB);
196
	memset(bp, Testbyte, Scratch);
197
	done = 0;
198
	dmastart((void *)PADDR(bp), Postincr, (void *)PADDR(&pat), Const,
199
		Testsize, &trendez, &done);
200
	sleep(&trendez, istestdmadone, &done);
201
	cachedinvse(bp, Scratch);
202
 
203
	if (((ulong *)bp)[0] != pat)
204
		panic("dmainit: copied incorrect data %#lux != %#lux",
205
			((ulong *)bp)[0], pat);
206
	for (n = Testsize; n < Scratch && bp[n] != Testbyte; n++)
207
		;
208
	if (n >= Scratch)
209
		panic("dmainit: ran wild over memory, clobbered ≥%,d bytes", n);
210
	if (bp[n] == Testbyte && n != Testsize)
211
		iprint("dma: %d-byte dma stopped after %d bytes!\n",
212
			Testsize, n);
213
}
214
 
215
/* addresses are physical */
216
int
217
dmastart(void *to, int tmode, void *from, int fmode, uint len, Rendez *rend,
218
	int *done)
219
{
220
	int irq, chan;
221
	uint ruplen;
222
	Dchan *cp;
223
	Regs *regs = (Regs *)PHYSSDMA;
224
	static Lock alloclck;
225
 
226
	/* allocate free irq (and chan) */
227
	ilock(&alloclck);
228
	for (irq = 0; irq < Nirq && xfer[irq].rend != nil; irq++)
229
		;
230
	if (irq >= Nirq)
231
		panic("dmastart: no available irqs; too many concurrent dmas");
232
	chan = irq;
233
	xfer[irq].rend = rend;			/* for wakeup at intr time */
234
	xfer[irq].done = done;
235
	*done = 0;
236
	iunlock(&alloclck);
237
 
238
	ruplen = ROUNDUP(len, sizeof(ulong));
239
	assert(to != from);
240
 
241
	cp = regs->chan + chan;
242
	cp->ccr &= ~Enable;			/* paranoia */
243
	cp->cicr = 0;
244
	regs->irqen[irq] &= ~(1 << chan);
245
	coherence();
246
 
247
	cp->csdp = 2;				/* 2 = log2(sizeof(ulong)) */
248
	cp->cssa = (uintptr)from;
249
	cp->cdsa = (uintptr)to;
250
	cp->ccr = tmode << 14 | fmode << 12;
251
	cp->csei = cp->csfi = cp->cdei = cp->cdfi = 1;
252
	cp->cen = ruplen / sizeof(ulong);	/* ulongs / frame */
253
	cp->cfn = 1;				/* 1 frame / xfer */
254
	cp->cicr = Blocki;			/* intr at end of block */
255
 
256
	regs->irqen[irq] |= 1 << chan;
257
	coherence();
258
 
259
	cp->ccr |= Enable;			/* fire! */
260
	coherence();
261
 
262
	return irq;
263
}