Setting up repository
[linux-libre-firmware.git] / ath9k_htc / sboot / magpie_1_1 / sboot / dma_engine / src / dma_engine.c
1 /*
2  * Copyright (c) 2013 Qualcomm Atheros, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted (subject to the limitations in the
7  * disclaimer below) provided that the following conditions are met:
8  *
9  *  * Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  *  * Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the
15  *    distribution.
16  *
17  *  * Neither the name of Qualcomm Atheros nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific prior written permission.
20  *
21  * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
22  * GRANTED BY THIS LICENSE.  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT
23  * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
24  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
27  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
30  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
32  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
33  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34  */
35 /*
36  * @File: dma_engine.c
37  * 
38  * @Abstract: DMA engine for Magpie
39  * 
40  * @Notes:
41  */
42 #include "sys_cfg.h"
43 #include "dt_defs.h"
44 #include "reg_defs.h"
45 #include "desc.h"
46
47 #include <osapi.h>
48 //#include <HIF_api.h>
49 #include <dma_engine_api.h>
50 #include <Magpie_api.h>
51 #include <vdesc_api.h>
52 #include <adf_os_mem.h> 
53 #include <adf_os_io.h>
54
55 //#include "HIF_usb.h"
56
57 //HIF_USB_CONTEXT g_hifUSBCtx;
58
59 #define VDESC_TO_USBDESC(vdesc)     (struct zsDmaDesc *)((vdesc)->hw_desc_buf)
60
61 static void relinkUSBDescToVdesc(VBUF *buf, struct zsDmaDesc* desc);
62 static void config_queue(struct zsDmaQueue *q, VDESC *desc_list);
63
64 #if ENABLE_SW_SWAP_DATA_MODE
65 static void swapData(struct zsDmaDesc* usbDesc);
66 #endif
67
68 static void init_usb_desc(struct zsDmaDesc *usbDesc)
69 {
70     usbDesc->status = ZM_OWN_BITS_SW;
71     usbDesc->ctrl = 0;
72     usbDesc->dataSize = 0;
73     usbDesc->totalLen = 0;
74     usbDesc->lastAddr = 0;
75     usbDesc->dataAddr = 0;
76     usbDesc->nextAddr = 0;    
77 }
78
79 void _DMAengine_init() 
80 {
81
82 }
83
84 void _DMAengine_init_rx_queue(struct zsDmaQueue *q) 
85 {
86     VDESC *desc;
87     struct zsDmaDesc *usbDesc;
88     
89     desc = VDESC_alloc_vdesc();
90     if ( desc != NULL ) {
91         usbDesc = VDESC_TO_USBDESC(desc);
92         init_usb_desc(usbDesc);
93         
94         q->head = q->terminator = usbDesc;
95     }   
96 }
97
98 void _DMAengine_init_tx_queue(struct zsTxDmaQueue *q) 
99 {
100     _DMAengine_init_rx_queue((struct zsDmaQueue *)q);
101     q->xmited_buf_head = NULL;
102     q->xmited_buf_tail = NULL;     
103 }
104
105 #if ENABLE_SW_SWAP_DATA_MODE
106
107 static void swapData(struct zsDmaDesc* usbDesc)
108 {
109     int len = (usbDesc->dataSize & 0xfffffffc) >> 2;
110     int i;
111     A_UINT32 *dataAddr = (A_UINT32 *)usbDesc->dataAddr;
112     A_UINT32 data;
113     
114     if ( ( usbDesc->dataSize & 3 ) != 0 ) {
115         len += 1;
116     }
117     
118     for ( i = 0; i < len; i++ ) {
119         data = dataAddr[i];
120         
121         dataAddr[i] = __bswap32(data);
122     }    
123 }
124
125 #endif
126
127 void _DMAengine_return_recv_buf(struct zsDmaQueue *q, VBUF *buf)
128 {    
129     /* Re-link the VDESC of buf into USB descriptor list & queue the descriptors 
130        into downQ
131      */     
132     config_queue(q, buf->desc_list);   
133     VBUF_free_vbuf(buf);              
134 }
135
136 static void config_queue(struct zsDmaQueue *q, VDESC *desc_list)
137 {   
138     VDESC *theDesc;
139     struct zsDmaDesc *usbDesc;
140     struct zsDmaDesc* prevUsbDesc = NULL;
141     struct zsDmaDesc* headUsbDesc;
142         
143     theDesc = desc_list;
144     while ( theDesc != NULL ) {            
145         usbDesc = (struct zsDmaDesc *)VDESC_get_hw_desc(theDesc);
146         init_usb_desc(usbDesc);
147        
148         theDesc->data_offset = 0; //RAY 0723
149         usbDesc->dataAddr = (volatile u32_t)(theDesc->buf_addr + theDesc->data_offset);
150         usbDesc->dataSize = theDesc->buf_size;
151         
152         if ( prevUsbDesc == NULL ) {
153             headUsbDesc = usbDesc;
154             prevUsbDesc = usbDesc;
155         } else {
156             prevUsbDesc->nextAddr = usbDesc;
157             prevUsbDesc = usbDesc;
158         }                
159         
160         theDesc = theDesc->next_desc;
161     }
162     
163     headUsbDesc->lastAddr = prevUsbDesc;
164     DMA_Engine_reclaim_packet(q, headUsbDesc);   
165                     
166     return;
167 }
168
169 //#define MAX_TX_BUF_SIZE            ZM_BLOCK_SIZE
170 //#define MAX_TX_BUF_SIZE            1600
171
172 void _DMAengine_config_rx_queue(struct zsDmaQueue *q, int num_desc, int buf_size)
173 {
174     int i;
175     VDESC *desc;
176     VDESC *head = NULL;
177         
178     for(i=0; i < num_desc; i++)
179     {
180         desc = VDESC_alloc_vdesc();
181         
182         adf_os_assert(desc != NULL);
183         
184         desc->buf_addr = (A_UINT8 *)adf_os_mem_alloc(buf_size);
185         desc->buf_size = buf_size;
186         desc->next_desc = NULL;
187         desc->data_offset = 0;
188         desc->data_size = 0;
189         desc->control = 0;
190                
191         if ( head == NULL )
192         {
193             head = desc;
194         }
195         else
196         {
197             desc->next_desc = head;
198             head = desc;
199         }
200     }         
201     
202     config_queue(q, head);          
203 }
204
205 void _DMAengine_xmit_buf(struct zsTxDmaQueue *q, VBUF *buf)
206 {
207     VDESC *currVdesc;
208     struct zsDmaDesc* usbDesc;
209     struct zsDmaDesc* prevUsbDesc = NULL;
210     struct zsDmaDesc* headUsbDesc;   
211         
212     /* Re-link the VDESC of buf into USB descriptor list & queue the descriptors 
213        into upQ
214      */
215     currVdesc = (VDESC *)buf->desc_list;
216     while(currVdesc != NULL) {
217         
218         usbDesc = (struct zsDmaDesc *)currVdesc->hw_desc_buf;
219                 
220         init_usb_desc(usbDesc);
221         usbDesc->dataSize = currVdesc->data_size;
222         usbDesc->dataAddr = (volatile u32_t)(currVdesc->buf_addr + currVdesc->data_offset);
223         usbDesc->ctrl = 0;
224         usbDesc->status = 0;
225
226 #if ENABLE_SW_SWAP_DATA_MODE && ENABLE_SWAP_DATA_MODE == 0
227         swapData(usbDesc);
228 #endif
229
230         if ( prevUsbDesc == NULL ) {
231             headUsbDesc = usbDesc;
232             
233             usbDesc->ctrl |= ZM_FS_BIT;
234             
235             // how to get the total len???
236             usbDesc->totalLen = buf->buf_length;
237             prevUsbDesc = usbDesc;
238         }
239         else {
240             prevUsbDesc->nextAddr = usbDesc;
241             prevUsbDesc = usbDesc;
242         }
243              
244         currVdesc = currVdesc->next_desc;
245     }
246
247     usbDesc->ctrl |= ZM_LS_BIT;
248     headUsbDesc->lastAddr = usbDesc;
249
250     if ( q->xmited_buf_head == NULL && q->xmited_buf_tail == NULL ) {
251         q->xmited_buf_head = buf;
252         q->xmited_buf_tail = buf;
253         q->xmited_buf_head->next_buf = q->xmited_buf_tail;
254     }
255     else {
256         q->xmited_buf_tail->next_buf = buf;
257         q->xmited_buf_tail = buf;
258     }
259
260     DMA_Engine_put_packet((struct zsDmaQueue *)q, headUsbDesc); 
261 }
262     
263 void _DMAengine_flush_xmit(struct zsDmaQueue *q)
264 {
265 }
266
267 int _DMAengine_has_compl_packets(struct zsDmaQueue *q)
268 {
269     int has_compl_pkts = 0;
270     
271     if ((q->head != q->terminator) && 
272         ((q->head->status & ZM_OWN_BITS_MASK) != ZM_OWN_BITS_HW)) {
273         has_compl_pkts = 1;            
274     }
275     
276     return has_compl_pkts;
277 }
278     
279 VBUF* _DMAengine_reap_recv_buf(struct zsDmaQueue *q)
280 {
281     struct zsDmaDesc* desc;
282     VBUF *buf;
283     //int i;
284     //u8_t *tbuf = (u8_t *)desc->dataAddr;
285             
286     desc = DMA_Engine_get_packet(q);            
287     
288     if(!desc)
289        return NULL;
290
291 #if ENABLE_SW_SWAP_DATA_MODE && ENABLE_SWAP_DATA_MODE == 0
292     swapData(desc);
293 #endif
294     
295     buf = VBUF_alloc_vbuf();
296     adf_os_assert(buf != NULL);
297     
298     relinkUSBDescToVdesc(buf, desc);
299     return buf;
300 }
301     
302 VBUF* _DMAengine_reap_xmited_buf(struct zsTxDmaQueue *q)
303 {
304     struct zsDmaDesc* desc;
305     VBUF *sentBuf;
306     
307     desc = DMA_Engine_get_packet((struct zsDmaQueue *)q);
308     
309     if(!desc)
310        return NULL;
311
312     // assert g_hifUSBCtx.upVbufQ.head is not null
313     // assert g_hifUSBCtx.upVbufQ.tail is not null  
314     sentBuf = q->xmited_buf_head;
315     if ( q->xmited_buf_head == q->xmited_buf_tail ) {
316         q->xmited_buf_head = NULL;
317         q->xmited_buf_tail = NULL;
318     } else {        
319         q->xmited_buf_head = q->xmited_buf_head->next_buf;       
320     }
321     
322     sentBuf->next_buf = NULL;
323     relinkUSBDescToVdesc(sentBuf, desc);
324     return sentBuf;
325 }
326
327 void _DMAengine_desc_dump(struct zsDmaQueue *q)
328 {
329     u32_t i=0;
330     struct zsDmaDesc* tmpDesc;
331         
332     tmpDesc = q->head;
333
334     do {
335         if( tmpDesc == q->terminator )
336         {
337 #ifdef DESC_DUMP_BOTH_DESCnDATA
338             A_PRINTF("0x%08x(0x%08x,T)]", tmpDesc, tmpDesc->dataAddr);
339 #else
340             A_PRINTF("0x%08x(T)]", tmpDesc);
341 #endif
342             break;
343         }
344         else
345 #ifdef DESC_DUMP_BOTH_DESCnDATA
346             A_PRINTF("0x%08x(0x%08x,%c)->", tmpDesc, tmpDesc->dataAddr, (tmpDesc->status&ZM_OWN_BITS_HW)?'H':'S');
347 #else
348             A_PRINTF("0x%08x(%c)->", tmpDesc, (tmpDesc->status&ZM_OWN_BITS_HW)?'H':'S');
349 #endif
350         
351         if( (++i%5)==0 ) 
352         {
353             A_PRINTF("\n\r   ");
354         }   
355         
356         tmpDesc = tmpDesc->nextAddr;            
357     }while(1);   
358     A_PRINTF("\n\r"); 
359 }
360     
361 /* the exported entry point into this module. All apis are accessed through
362  * function pointers */
363 void dma_engine_module_install(struct dma_engine_api *apis)
364 {    
365         /* hook in APIs */
366     apis->_init                 = _DMAengine_init;
367     apis->_config_rx_queue      = _DMAengine_config_rx_queue;
368     apis->_xmit_buf             = _DMAengine_xmit_buf;
369     apis->_flush_xmit           = _DMAengine_flush_xmit;
370     apis->_reap_recv_buf        = _DMAengine_reap_recv_buf;
371     apis->_return_recv_buf      = _DMAengine_return_recv_buf;
372     apis->_reap_xmited_buf      = _DMAengine_reap_xmited_buf;
373     apis->_swap_data            = swapData;
374     apis->_has_compl_packets    = _DMAengine_has_compl_packets;
375     apis->_init_rx_queue        = _DMAengine_init_rx_queue;
376     apis->_init_tx_queue        = _DMAengine_init_tx_queue;    
377     apis->_desc_dump            = _DMAengine_desc_dump;
378     apis->_get_packet           = zfDmaGetPacket;
379     apis->_reclaim_packet       = zfDmaReclaimPacket;
380     apis->_put_packet           = zfDmaPutPacket;
381     
382         /* save ptr to the ptr to the context for external code to inspect/modify internal module state */
383     //apis->pReserved = &g_pMboxHWContext;
384 }
385  
386 static void relinkUSBDescToVdesc(VBUF *buf, struct zsDmaDesc* desc)
387 {
388     VDESC *vdesc;
389     VDESC *prevVdesc = NULL;
390     struct zsDmaDesc *currDesc = desc;
391                  
392     vdesc = VDESC_HW_TO_VDESC(currDesc);          
393     buf->desc_list = vdesc;
394     buf->buf_length = currDesc->totalLen;        
395     
396     while(currDesc != NULL) {      
397         vdesc->data_size = currDesc->dataSize;                   
398         //vdesc->data_offset = 0; // TODO: bad!!
399         
400         if ( prevVdesc == NULL ) {
401             prevVdesc = vdesc;
402         } else {
403             prevVdesc->next_desc = vdesc;
404             prevVdesc = vdesc;
405         }
406         
407         if ( currDesc->ctrl & ZM_LS_BIT ) {
408             vdesc->next_desc = NULL;
409             currDesc = NULL;
410             break;
411         } else {
412             currDesc = currDesc->nextAddr;
413             vdesc = VDESC_HW_TO_VDESC(currDesc);
414         }
415     }        
416 }