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
 * bcm2835 dma controller
3
 *
4
 * simplest to use only channels 0-6
5
 *	channels 7-14 have reduced functionality
6
 *	channel 15 is at a weird address
7
 *	channels 0 and 15 have an "external 128 bit 8 word read FIFO"
8
 *	  for memory to memory transfers
9
 *
10
 * Experiments show that only channels 2-5,11-12 work with mmc
11
 */
12
 
13
#include "u.h"
14
#include "../port/lib.h"
15
#include "../port/error.h"
16
#include "mem.h"
17
#include "dat.h"
18
#include "fns.h"
19
#include "io.h"
20
 
21
#define DMAREGS	(VIRTIO+0x7000)
22
 
23
#define DBG	if(Dbg)
24
 
25
enum {
26
	Nchan		= 7,		/* number of dma channels */
27
	Regsize		= 0x100,	/* size of regs for each chan */
28
	Cbalign		= 32,		/* control block byte alignment */
29
	Dbg		= 0,
30
 
31
	/* registers for each dma controller */
32
	Cs		= 0x00>>2,
33
	Conblkad	= 0x04>>2,
34
	Ti		= 0x08>>2,
35
	Sourcead	= 0x0c>>2,
36
	Destad		= 0x10>>2,
37
	Txfrlen		= 0x14>>2,
38
	Stride		= 0x18>>2,
39
	Nextconbk	= 0x1c>>2,
40
	Debug		= 0x20>>2,
41
 
42
	/* collective registers */
43
	Intstatus	= 0xfe0>>2,
44
	Enable		= 0xff0>>2,
45
 
46
	/* Cs */
47
	Reset		= 1<<31,
48
	Abort		= 1<<30,
49
	Error		= 1<<8,
50
	Waitwrite	= 1<<6,
51
	Waitdreq	= 1<<5,
52
	Paused		= 1<<4,
53
	Dreq		= 1<<3,
54
	Int		= 1<<2,
55
	End		= 1<<1,
56
	Active		= 1<<0,
57
 
58
	/* Ti */
59
	Permapshift= 16,
60
	Srcignore	= 1<<11,
61
	Srcdreq		= 1<<10,
62
	Srcwidth128	= 1<<9,
63
	Srcinc		= 1<<8,
64
	Destignore	= 1<<7,
65
	Destdreq	= 1<<6,
66
	Destwidth128	= 1<<5,
67
	Destinc		= 1<<4,
68
	Waitresp	= 1<<3,
69
	Tdmode		= 1<<1,
70
	Inten		= 1<<0,
71
 
72
	/* Debug */
73
	Lite		= 1<<28,
74
	Clrerrors	= 7<<0,
75
};
76
 
77
typedef struct Ctlr Ctlr;
78
typedef struct Cb Cb;
79
 
80
struct Ctlr {
81
	u32int	*regs;
82
	Cb	*cb;
83
	Rendez	r;
84
	int	dmadone;
85
};
86
 
87
struct Cb {
88
	u32int	ti;
89
	u32int	sourcead;
90
	u32int	destad;
91
	u32int	txfrlen;
92
	u32int	stride;
93
	u32int	nextconbk;
94
	u32int	reserved[2];
95
};
96
 
97
static Ctlr dma[Nchan];
98
static u32int *dmaregs = (u32int*)DMAREGS;
99
 
100
static void
101
dump(char *msg, uchar *p, int n)
102
{
103
	print("%s", msg);
104
	while(n-- > 0)
105
		print(" %2.2x", *p++);
106
	print("\n");
107
}
108
 
109
static void
110
dumpdregs(char *msg, u32int *r)
111
{
112
	int i;
113
 
114
	print("%s: %#p =", msg, r);
115
	for(i = 0; i < 9; i++)
116
		print(" %8.8uX", r[i]);
117
	print("\n");
118
}
119
 
120
static int
121
dmadone(void *a)
122
{
123
	return ((Ctlr*)a)->dmadone;
124
}
125
 
126
static void
127
dmainterrupt(Ureg*, void *a)
128
{
129
	Ctlr *ctlr;
130
 
131
	ctlr = a;
132
	ctlr->regs[Cs] = Int;
133
	ctlr->dmadone = 1;
134
	wakeup(&ctlr->r);
135
}
136
 
137
void
138
dmastart(int chan, int dev, int dir, void *src, void *dst, int len)
139
{
140
	Ctlr *ctlr;
141
	Cb *cb;
142
	int ti;
143
 
144
	ctlr = &dma[chan];
145
	if(ctlr->regs == nil){
146
		ctlr->regs = (u32int*)(DMAREGS + chan*Regsize);
147
		ctlr->cb = xspanalloc(sizeof(Cb), Cbalign, 0);
148
		assert(ctlr->cb != nil);
149
		dmaregs[Enable] |= 1<<chan;
150
		ctlr->regs[Cs] = Reset;
151
		while(ctlr->regs[Cs] & Reset)
152
			;
153
		intrenable(IRQDMA(chan), dmainterrupt, ctlr, 0, "dma");
154
	}
155
	cb = ctlr->cb;
156
	ti = 0;
157
	switch(dir){
158
	case DmaD2M:
159
		cachedwbinvse(dst, len);
160
		ti = Srcdreq | Destinc;
161
		cb->sourcead = DMAIO(src);
162
		cb->destad = DMAADDR(dst);
163
		break;
164
	case DmaM2D:
165
		cachedwbse(src, len);
166
		ti = Destdreq | Srcinc;
167
		cb->sourcead = DMAADDR(src);
168
		cb->destad = DMAIO(dst);
169
		break;
170
	case DmaM2M:
171
		cachedwbse(src, len);
172
		cachedwbinvse(dst, len);
173
		ti = Srcinc | Destinc;
174
		cb->sourcead = DMAADDR(src);
175
		cb->destad = DMAADDR(dst);
176
		break;
177
	}
178
	cb->ti = ti | dev<<Permapshift | Inten;
179
	cb->txfrlen = len;
180
	cb->stride = 0;
181
	cb->nextconbk = 0;
182
	cachedwbse(cb, sizeof(Cb));
183
	ctlr->regs[Cs] = 0;
184
	microdelay(1);
185
	ctlr->regs[Conblkad] = DMAADDR(cb);
186
	DBG print("dma start: %ux %ux %ux %ux %ux %ux\n",
187
		cb->ti, cb->sourcead, cb->destad, cb->txfrlen,
188
		cb->stride, cb->nextconbk);
189
	DBG print("intstatus %ux\n", dmaregs[Intstatus]);
190
	dmaregs[Intstatus] = 0;
191
	ctlr->regs[Cs] = Int;
192
	microdelay(1);
193
	coherence();
194
	DBG dumpdregs("before Active", ctlr->regs);
195
	ctlr->regs[Cs] = Active;
196
	DBG dumpdregs("after Active", ctlr->regs);
197
}
198
 
199
int
200
dmawait(int chan)
201
{
202
	Ctlr *ctlr;
203
	u32int *r;
204
	int s;
205
 
206
	ctlr = &dma[chan];
207
	tsleep(&ctlr->r, dmadone, ctlr, 3000);
208
	ctlr->dmadone = 0;
209
	r = ctlr->regs;
210
	DBG dumpdregs("after sleep", r);
211
	s = r[Cs];
212
	if((s & (Active|End|Error)) != End){
213
		print("dma chan %d %s Cs %ux Debug %ux\n", chan,
214
			(s&End)? "error" : "timeout", s, r[Debug]);
215
		r[Cs] = Reset;
216
		r[Debug] = Clrerrors;
217
		return -1;
218
	}
219
	r[Cs] = Int|End;
220
	return 0;
221
}