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