Home | History | Annotate | Line # | Download | only in at91
at91pdcvar.h revision 1.2.42.1
      1  1.2.42.1   tls /*	$Id: at91pdcvar.h,v 1.2.42.1 2012/11/20 03:01:03 tls 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.2.42.1   tls 	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.2.42.1   tls 	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