1 /* $Id: at91pdcvar.h,v 1.2 2008/07/03 01:15:38 matt Exp $ */
6 #include <arm/at91/at91pdcreg.h>
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 */
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) */
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; \
29 bus_dmamap_sync((_dmat), buf->buf_dmamap, 0, \
30 buf->buf_len, (_sync)); \
32 bus_dmamap_unload((_dmat), buf->buf_dmamap); \
33 buf->buf_arg = 0; buf->buf_len = 0; \
35 (_pq)->q_ndx = i ^ 1; \
39 } while (/*CONSTCOND*/0)
41 #define AT91PDC_UNLOAD_QUEUE(_pq, _dmat, _sync, _free, _idle) \
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)
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 */
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
,
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
;
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
);
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
,
110 at91pdc_fifo_t
*fifo
,
116 /* then check if we can queue new block */
117 if (bus_space_read_4(iot
, ioh
, offset
+ PDC_RNCR
))
119 if (fifo
->f_pdc_space
< chunk_size
) {
123 /* fifo has enough space left for next chunk! */
124 bus_dmamap_sync(dmat
,
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
;
135 /* now check if we need to re-synchronize last read chunk too */
136 al
= fifo
->f_pdc_rd_ndx
% chunk_size
;
138 bus_dmamap_sync(dmat
,
142 BUS_DMASYNC_PREREAD
);
147 static __inline
void AT91PDC_FIFO_POSTREAD(bus_space_tag_t iot
,
148 bus_space_handle_t ioh
,
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: */
158 cc
= fifo
->f_buf_size
- fifo
->f_pdc_rd_ndx
;
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
;
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) {
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
;
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
,
207 at91pdc_fifo_t
*fifo
,
210 if (bus_space_read_4(iot
, ioh
, offset
+ PDC_TNCR
) != 0)
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
);
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
);
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
,
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
;
242 static __inline
void AT91PDC_FIFO_POSTWRITE(bus_space_tag_t iot
,
243 bus_space_handle_t ioh
,
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: */
253 cc
= fifo
->f_buf_size
- fifo
->f_pdc_wr_ndx
;
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
;
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
;
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
;
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_