No empty .Rs/.Re
[netbsd-mini2440.git] / sys / arch / arm / at91 / at91pdcvar.h
blobe69d3376dfbe27a7dc59c4a6a882f7ba4317a1cc
1 /* $Id: at91pdcvar.h,v 1.2 2008/07/03 01:15:38 matt Exp $ */
3 #ifndef _AT91PDCVAR_H_
4 #define _AT91PDCVAR_H_
6 #include <arm/at91/at91pdcreg.h>
7 #include <sys/param.h>
9 #if UNTESTED
11 typedef struct at91pdc_buf {
12 void *buf_arg; /* argument (mbuf or other data) */
13 int buf_len; /* length of data sent / recv */
14 bus_dmamap_t buf_dmamap; /* dma map */
15 } at91pdc_buf_t;
17 typedef struct at91pdc_queue {
18 at91pdc_buf_t q_buf[2]; /* two buffers */
19 unsigned q_ndx; /* buffer being sent (if q_len > 0) */
20 unsigned q_len; /* number of buffers being used (<= 2) */
21 } at91pdc_queue_t;
23 #define AT91PDC_UNLOAD_BUF(_pq, _dmat, _sync, _free) do { \
24 unsigned _i = (_pq)->q_ndx % 2; \
25 at91pdc_buf_t *_buf = &(_pq)->q_buf[i]; \
26 void *_arg = _buf->buf_arg; \
28 if (_sync) { \
29 bus_dmamap_sync((_dmat), buf->buf_dmamap, 0, \
30 buf->buf_len, (_sync)); \
31 } \
32 bus_dmamap_unload((_dmat), buf->buf_dmamap); \
33 buf->buf_arg = 0; buf->buf_len = 0; \
35 (_pq)->q_ndx = i ^ 1; \
36 (_pq)->q_len--; \
38 (_free)(_arg); \
39 } while (/*CONSTCOND*/0)
41 #define AT91PDC_UNLOAD_QUEUE(_pq, _dmat, _sync, _free, _idle) \
42 do { \
43 if ((_pq)->q_len > 1) \
44 AT91PDC_UNLOAD_BUF(_pq, _dmat, _sync, _free); \
45 if ((_idle) && (_pq)->q_len > 0) \
46 AT91PDC_UNLOAD_BUF(_pq, _dmat, _sync, _free); \
47 } while (/*CONSTCOND*/0)
49 #endif /* UNTESTED */
52 typedef struct at91pdc_fifo {
53 bus_dmamap_t f_dmamap; /* DMA map */
54 void *f_buf; /* buffer address */
55 int f_buf_size; /* size of the fifo */
56 int f_ndx; /* current read/write index */
57 int f_length; /* number of bytes in fifo */
59 bus_addr_t f_buf_addr; /* buffer bus addr */
60 int f_pdc_rd_ndx; /* PDC read index */
61 int f_pdc_wr_ndx; /* PDC write index */
62 int f_pdc_space; /* number of bytes allocated for pdc */
63 } at91pdc_fifo_t;
65 static __inline int AT91PDC_FIFO_EMPTY(at91pdc_fifo_t *fifo)
67 return fifo->f_length == 0;
70 static __inline int AT91PDC_FIFO_FULL(at91pdc_fifo_t *fifo)
72 return fifo->f_length >= fifo->f_buf_size;
75 static __inline int AT91PDC_FIFO_SPACE(at91pdc_fifo_t *fifo)
77 return fifo->f_buf_size - fifo->f_length;
81 static __inline void AT91PDC_RESET_FIFO(bus_space_tag_t iot,
82 bus_space_handle_t ioh,
83 bus_dma_tag_t dmat,
84 uint offset,
85 at91pdc_fifo_t *fifo,
86 int rw)
88 fifo->f_ndx = fifo->f_length = 0;
90 fifo->f_pdc_rd_ndx = fifo->f_pdc_wr_ndx = 0;
91 fifo->f_pdc_space = fifo->f_buf_size;
93 if (!rw) {
94 bus_space_write_4(iot, ioh, offset + PDC_RNCR, 0);
95 bus_space_write_4(iot, ioh, offset + PDC_RCR, 0);
96 bus_space_write_4(iot, ioh, offset + PDC_RNPR, fifo->f_buf_addr);
97 bus_space_write_4(iot, ioh, offset + PDC_RPR, fifo->f_buf_addr);
98 } else {
99 bus_space_write_4(iot, ioh, offset + PDC_TNCR, 0);
100 bus_space_write_4(iot, ioh, offset + PDC_TCR, 0);
101 bus_space_write_4(iot, ioh, offset + PDC_TNPR, fifo->f_buf_addr);
102 bus_space_write_4(iot, ioh, offset + PDC_TPR, fifo->f_buf_addr);
106 static __inline int AT91PDC_FIFO_PREREAD(bus_space_tag_t iot,
107 bus_space_handle_t ioh,
108 bus_dma_tag_t dmat,
109 uint offset,
110 at91pdc_fifo_t *fifo,
111 uint chunk_size)
113 int al;
114 int ret = 1;
116 /* then check if we can queue new block */
117 if (bus_space_read_4(iot, ioh, offset + PDC_RNCR))
118 goto get_out;
119 if (fifo->f_pdc_space < chunk_size) {
120 ret = 0;
121 goto get_out;
123 /* fifo has enough space left for next chunk! */
124 bus_dmamap_sync(dmat,
125 fifo->f_dmamap,
126 fifo->f_pdc_wr_ndx,
127 chunk_size,
128 BUS_DMASYNC_PREREAD);
129 bus_space_write_4(iot, ioh, offset + PDC_RNPR, fifo->f_buf_addr + fifo->f_pdc_wr_ndx);
130 bus_space_write_4(iot, ioh, offset + PDC_RNCR, chunk_size);
131 if ((fifo->f_pdc_wr_ndx += chunk_size) >= fifo->f_buf_size)
132 fifo->f_pdc_wr_ndx = 0;
133 fifo->f_pdc_space -= chunk_size;
134 get_out:
135 /* now check if we need to re-synchronize last read chunk too */
136 al = fifo->f_pdc_rd_ndx % chunk_size;
137 if (al) {
138 bus_dmamap_sync(dmat,
139 fifo->f_dmamap,
140 fifo->f_pdc_rd_ndx,
141 chunk_size - al,
142 BUS_DMASYNC_PREREAD);
144 return ret;
147 static __inline void AT91PDC_FIFO_POSTREAD(bus_space_tag_t iot,
148 bus_space_handle_t ioh,
149 bus_dma_tag_t dmat,
150 uint offset,
151 at91pdc_fifo_t *fifo)
153 u_int32_t pdc_ptr = bus_space_read_4(iot, ioh, offset + PDC_RPR);
154 int32_t cc = pdc_ptr - fifo->f_buf_addr - fifo->f_pdc_rd_ndx;
156 /* handle fifo wrapping: */
157 if (cc < 0) {
158 cc = fifo->f_buf_size - fifo->f_pdc_rd_ndx;
159 if (cc > 0) {
160 bus_dmamap_sync(dmat, fifo->f_dmamap, fifo->f_pdc_rd_ndx, cc,
161 BUS_DMASYNC_POSTREAD);
162 fifo->f_length += cc;
163 fifo->f_pdc_rd_ndx += cc;
165 fifo->f_pdc_rd_ndx = 0;
166 cc = pdc_ptr - fifo->f_buf_addr;
169 if (cc > 0) {
170 /* data has been received! */
171 bus_dmamap_sync(dmat, fifo->f_dmamap, fifo->f_pdc_rd_ndx, cc,
172 BUS_DMASYNC_POSTREAD);
173 fifo->f_length += cc;
174 fifo->f_pdc_rd_ndx += cc;
178 static __inline void *AT91PDC_FIFO_RDPTR(at91pdc_fifo_t *fifo, int *num_bytes)
180 if (fifo->f_length <= 0) {
181 return NULL;
183 int contig_bytes = fifo->f_buf_size - fifo->f_ndx;
184 if (contig_bytes > fifo->f_length)
185 contig_bytes = fifo->f_length;
186 *num_bytes = contig_bytes;
187 return (void*)((uintptr_t)fifo->f_buf + fifo->f_ndx);
190 static __inline void AT91PDC_FIFO_READ(at91pdc_fifo_t *fifo, int bytes_read)
192 if (bytes_read > fifo->f_length)
193 bytes_read = fifo->f_length;
194 int contig_bytes = fifo->f_buf_size - fifo->f_ndx;
195 fifo->f_length -= bytes_read;
196 fifo->f_pdc_space += bytes_read;
197 if (bytes_read < contig_bytes)
198 fifo->f_ndx += bytes_read;
199 else
200 fifo->f_ndx = bytes_read - contig_bytes;
203 static __inline int AT91PDC_FIFO_PREWRITE(bus_space_tag_t iot,
204 bus_space_handle_t ioh,
205 bus_dma_tag_t dmat,
206 uint offset,
207 at91pdc_fifo_t *fifo,
208 uint max_chunk_size)
210 if (bus_space_read_4(iot, ioh, offset + PDC_TNCR) != 0)
211 return 1;
212 int len = fifo->f_buf_size - fifo->f_pdc_rd_ndx;
213 int max_len = fifo->f_length - (fifo->f_buf_size - fifo->f_pdc_space);
214 if (len > max_len)
215 len = max_len;
216 if (len > max_chunk_size)
217 len = max_chunk_size;
218 if (len > fifo->f_pdc_space)
219 panic("%s: len %d > pdc_space (f_length=%d space=%d size=%d)",
220 __FUNCTION__, len, fifo->f_length, fifo->f_pdc_space, fifo->f_buf_size);
221 if (len == 0)
222 return 0;
223 if (len < 0)
224 panic("%s: len < 0 (f_length=%d space=%d size=%d)",
225 __FUNCTION__, fifo->f_length, fifo->f_pdc_space, fifo->f_buf_size);
227 /* there's something to write */
228 bus_dmamap_sync(dmat,
229 fifo->f_dmamap,
230 fifo->f_pdc_rd_ndx,
231 len,
232 BUS_DMASYNC_PREWRITE);
233 bus_space_write_4(iot, ioh, offset + PDC_TNPR, fifo->f_buf_addr + fifo->f_pdc_rd_ndx);
234 bus_space_write_4(iot, ioh, offset + PDC_TNCR, len);
235 if ((fifo->f_pdc_rd_ndx += len) >= fifo->f_buf_size)
236 fifo->f_pdc_rd_ndx = 0;
237 fifo->f_pdc_space -= len;
239 return 1;
242 static __inline void AT91PDC_FIFO_POSTWRITE(bus_space_tag_t iot,
243 bus_space_handle_t ioh,
244 bus_dma_tag_t dmat,
245 uint offset,
246 at91pdc_fifo_t *fifo)
248 u_int32_t pdc_ptr = bus_space_read_4(iot, ioh, offset + PDC_TPR);
249 int32_t cc = pdc_ptr - fifo->f_buf_addr - fifo->f_pdc_wr_ndx;
251 /* handle fifo wrapping: */
252 if (cc < 0) {
253 cc = fifo->f_buf_size - fifo->f_pdc_wr_ndx;
254 if (cc > 0) {
255 bus_dmamap_sync(dmat, fifo->f_dmamap, fifo->f_pdc_wr_ndx, cc,
256 BUS_DMASYNC_POSTWRITE);
257 fifo->f_length -= cc;
258 fifo->f_pdc_space += cc;
260 fifo->f_pdc_wr_ndx = 0;
261 cc = pdc_ptr - fifo->f_buf_addr;
264 if (cc > 0) {
265 /* data has been sent! */
266 bus_dmamap_sync(dmat, fifo->f_dmamap, fifo->f_pdc_wr_ndx, cc,
267 BUS_DMASYNC_POSTWRITE);
268 fifo->f_length -= cc;
269 fifo->f_pdc_space += cc;
270 fifo->f_pdc_wr_ndx += cc;
274 static __inline void *AT91PDC_FIFO_WRPTR(at91pdc_fifo_t *fifo, int *max_bytes)
276 int space = fifo->f_buf_size - fifo->f_length;
277 if (space <= 0)
278 return NULL;
279 int contig_bytes = fifo->f_buf_size - fifo->f_ndx;
280 if (contig_bytes > space)
281 contig_bytes = space;
282 *max_bytes = contig_bytes;
283 return (void*)((uintptr_t)fifo->f_buf + fifo->f_ndx);
286 static __inline void AT91PDC_FIFO_WRITTEN(at91pdc_fifo_t *fifo, int bytes_written)
288 if (bytes_written > (fifo->f_buf_size - fifo->f_length))
289 bytes_written = (fifo->f_buf_size - fifo->f_length);
290 int contig_bytes = fifo->f_buf_size - fifo->f_ndx;
291 fifo->f_length += bytes_written;
292 if (bytes_written < contig_bytes)
293 fifo->f_ndx += bytes_written;
294 else
295 fifo->f_ndx = bytes_written - contig_bytes;
298 int at91pdc_alloc_fifo(bus_dma_tag_t dmat, at91pdc_fifo_t *fifo, int size, int flags);
300 #endif // !_AT91PDCVAR_H_