Home | History | Annotate | Line # | Download | only in at91
      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