xref: /netbsd-src/sys/arch/arm/at91/at91pdcvar.h (revision 08a4aba755ef4f463e005a94ee98c3f3ebc49090)
1 /*	$Id: at91pdcvar.h,v 1.3 2012/11/12 18:00:36 skrll Exp $	*/
2 
3 #ifndef	_AT91PDCVAR_H_
4 #define	_AT91PDCVAR_H_
5 
6 #include <arm/at91/at91pdcreg.h>
7 #include <sys/param.h>
8 
9 #if	UNTESTED
10 
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;
16 
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;
22 
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;			\
27 								\
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;			\
34 								\
35 	(_pq)->q_ndx = i ^ 1;					\
36 	(_pq)->q_len--;						\
37 								\
38 	(_free)(_arg);						\
39 } while (/*CONSTCOND*/0)
40 
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)
48 
49 #endif	/* UNTESTED */
50 
51 
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	*/
58 
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;
64 
AT91PDC_FIFO_EMPTY(at91pdc_fifo_t * fifo)65 static __inline int AT91PDC_FIFO_EMPTY(at91pdc_fifo_t *fifo)
66 {
67 	return fifo->f_length == 0;
68 }
69 
AT91PDC_FIFO_FULL(at91pdc_fifo_t * fifo)70 static __inline int AT91PDC_FIFO_FULL(at91pdc_fifo_t *fifo)
71 {
72 	return fifo->f_length >= fifo->f_buf_size;
73 }
74 
AT91PDC_FIFO_SPACE(at91pdc_fifo_t * fifo)75 static __inline int AT91PDC_FIFO_SPACE(at91pdc_fifo_t *fifo)
76 {
77 	return fifo->f_buf_size - fifo->f_length;
78 }
79 
80 
AT91PDC_RESET_FIFO(bus_space_tag_t iot,bus_space_handle_t ioh,bus_dma_tag_t dmat,uint offset,at91pdc_fifo_t * fifo,int rw)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)
87 {
88 	fifo->f_ndx = fifo->f_length = 0;
89 
90 	fifo->f_pdc_rd_ndx = fifo->f_pdc_wr_ndx = 0;
91 	fifo->f_pdc_space = fifo->f_buf_size;
92 
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);
103 	}
104 }
105 
AT91PDC_FIFO_PREREAD(bus_space_tag_t iot,bus_space_handle_t ioh,bus_dma_tag_t dmat,uint offset,at91pdc_fifo_t * fifo,uint chunk_size)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)
112 {
113 	int al;
114 	int ret = 1;
115 
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;
122 	}
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);
143 	}
144 	return ret;
145 }
146 
AT91PDC_FIFO_POSTREAD(bus_space_tag_t iot,bus_space_handle_t ioh,bus_dma_tag_t dmat,uint offset,at91pdc_fifo_t * fifo)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)
152 {
153 	uint32_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;
155 
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;
164 		}
165 		fifo->f_pdc_rd_ndx = 0;
166 		cc = pdc_ptr - fifo->f_buf_addr;
167 	}
168 
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;
175 	}
176 }
177 
AT91PDC_FIFO_RDPTR(at91pdc_fifo_t * fifo,int * num_bytes)178 static __inline void *AT91PDC_FIFO_RDPTR(at91pdc_fifo_t *fifo, int *num_bytes)
179 {
180 	if (fifo->f_length <= 0) {
181 		return NULL;
182 	}
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);
188 }
189 
AT91PDC_FIFO_READ(at91pdc_fifo_t * fifo,int bytes_read)190 static __inline void AT91PDC_FIFO_READ(at91pdc_fifo_t *fifo, int bytes_read)
191 {
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;
201 }
202 
AT91PDC_FIFO_PREWRITE(bus_space_tag_t iot,bus_space_handle_t ioh,bus_dma_tag_t dmat,uint offset,at91pdc_fifo_t * fifo,uint max_chunk_size)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)
209 {
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);
226 
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;
238 
239 	return 1;
240 }
241 
AT91PDC_FIFO_POSTWRITE(bus_space_tag_t iot,bus_space_handle_t ioh,bus_dma_tag_t dmat,uint offset,at91pdc_fifo_t * fifo)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)
247 {
248 	uint32_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;
250 
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;
259 		}
260 		fifo->f_pdc_wr_ndx = 0;
261 		cc = pdc_ptr - fifo->f_buf_addr;
262 	}
263 
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;
271 	}
272 }
273 
AT91PDC_FIFO_WRPTR(at91pdc_fifo_t * fifo,int * max_bytes)274 static __inline void *AT91PDC_FIFO_WRPTR(at91pdc_fifo_t *fifo, int *max_bytes)
275 {
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);
284 }
285 
AT91PDC_FIFO_WRITTEN(at91pdc_fifo_t * fifo,int bytes_written)286 static __inline void AT91PDC_FIFO_WRITTEN(at91pdc_fifo_t *fifo, int bytes_written)
287 {
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;
296 }
297 
298 int at91pdc_alloc_fifo(bus_dma_tag_t dmat, at91pdc_fifo_t *fifo, int size, int flags);
299 
300 #endif	// !_AT91PDCVAR_H_
301