05dc49f7b1b5b3c92f6d1d606fb9a65dbe18e0f9
[open-ath9k-htc-firmware.git] / target_firmware / magpie_fw_dev / build / magpie_1_1 / sboot / hif / dma_lib / dma_lib.c
1 #include <dt_defs.h>
2 #include <osapi.h>
3 #include <dma_engine_api.h>
4 #include <Magpie_api.h>
5 #include <vbuf_api.h>
6 #include <Magpie_api.h>
7
8 #include "dma_lib.h"
9 /***********************Constants***************************/
10
11 /**
12  * @brief Descriptor specific bitmaps
13  */
14 enum __dma_desc_status{
15     DMA_STATUS_OWN_DRV = 0x0,
16     DMA_STATUS_OWN_DMA = 0x1,
17     DMA_STATUS_OWN_MSK = 0x3
18 };
19
20 enum __dma_bit_op{
21     DMA_BIT_CLEAR  = 0x0,
22     DMA_BIT_SET    = 0x1
23 };
24
25 enum __dma_burst_size{
26     DMA_BURST_4W   = 0x00,
27     DMA_BURST_8W   = 0x01,
28     DMA_BURST_16W  = 0x02
29 };
30 enum __dma_byte_swap{
31     DMA_BYTE_SWAP_OFF = 0x00,
32     DMA_BYTE_SWAP_ON  = 0x01
33 };
34 /**
35 *  @brief Interrupt status bits
36  */
37 typedef enum __dma_intr_bits{
38     DMA_INTR_TX1_END   = (1 << 25),/*TX1 reached the end or Under run*/
39     DMA_INTR_TX0_END   = (1 << 24),/*TX0 reached the end or Under run*/
40     DMA_INTR_TX1_DONE  = (1 << 17),/*TX1 has transmitted a packet*/
41     DMA_INTR_TX0_DONE  = (1 << 16),/*TX1 has transmitted a packet*/
42     DMA_INTR_RX3_END   = (1 << 11),/*RX3 reached the end or Under run*/
43     DMA_INTR_RX2_END   = (1 << 10),/*RX2 reached the end or Under run*/
44     DMA_INTR_RX1_END   = (1 << 9), /*RX1 reached the end or Under run*/
45     DMA_INTR_RX0_END   = (1 << 8), /*RX0 reached the end or Under run*/
46     DMA_INTR_RX3_DONE  = (1 << 3), /*RX3 received a packet*/
47     DMA_INTR_RX2_DONE  = (1 << 2), /*RX2 received a packet*/
48     DMA_INTR_RX1_DONE  = (1 << 1), /*RX1 received a packet*/
49     DMA_INTR_RX0_DONE  = 1,        /*RX0 received a packet*/
50 }__dma_intr_bits_t;
51 /**
52  * @brief Base addresses for various HIF
53  */
54 typedef enum __dma_base_off{
55     DMA_BASE_OFF_HST  = 0x00053000,
56     DMA_BASE_OFF_GMAC = 0x00054000,
57     DMA_BASE_OFF_PCI  = DMA_BASE_OFF_HST,
58     DMA_BASE_OFF_PCIE = DMA_BASE_OFF_HST
59 }__dma_base_off_t;
60 /**
61  * @brief Engine offset to add for per engine register reads or
62  *        writes
63  */
64 typedef enum __dma_eng_off{
65     DMA_ENG_OFF_RX0 = 0x800,
66     DMA_ENG_OFF_RX1 = 0x900,
67     DMA_ENG_OFF_RX2 = 0xa00,
68     DMA_ENG_OFF_RX3 = 0xb00,
69     DMA_ENG_OFF_TX0 = 0xc00,
70     DMA_ENG_OFF_TX1 = 0xd00
71 }__dma_eng_off_t;
72 /**
73  *@brief DMA registers
74  */
75 typedef enum __dma_reg_off{
76     /**
77      * Common or Non Engine specific
78      */
79     DMA_REG_IFTYPE   = 0x00,/*XXX*/
80     DMA_REG_ISR      = 0x00,/*Interrupt Status Register*/
81     DMA_REG_IMR      = 0x04,/*Interrupt Mask Register*/
82     /**
83      * Transmit
84      */
85     DMA_REG_TXDESC   = 0x00,/*TX DP*/
86     DMA_REG_TXSTART  = 0x04,/*TX start*/
87     DMA_REG_INTRLIM  = 0x08,/*TX Interrupt limit*/
88     DMA_REG_TXBURST  = 0x0c,/*TX Burst Size*/
89     DMA_REG_TXSWAP   = 0x18,
90     /**
91      * Receive
92      */
93     DMA_REG_RXDESC   = 0x00,/*RX DP*/
94     DMA_REG_RXSTART  = 0x04,/*RX Start*/
95     DMA_REG_RXBURST  = 0x08,/*RX Burst Size*/
96     DMA_REG_RXPKTOFF = 0x0c,/*RX Packet Offset*/
97     DMA_REG_RXSWAP   = 0x1c
98 }__dma_reg_off_t;
99
100 /*******************************Data types******************************/
101
102 typedef struct zsDmaDesc    __dma_desc_t;
103
104 typedef struct zsDmaQueue   __dma_rxq_t;
105
106 typedef struct zsTxDmaQueue  __dma_txq_t;
107
108 /**
109  * @brief Register Address
110  */
111 typedef struct __dma_reg_addr{
112     __dma_base_off_t     base;/*Base address, Fixed*/
113     __dma_eng_off_t      eng;/*Engine offset, Fixed*/
114 }__dma_reg_addr_t;
115
116 /**
117  * @brief DMA engine's Queue
118  */
119 typedef struct __dma_eng_q{
120    __dma_reg_addr_t     addr;
121    union{
122         __dma_rxq_t          rx_q;
123         __dma_txq_t          tx_q;
124    }u;
125 }__dma_eng_q_t;
126
127 #define rxq         u.rx_q
128 #define txq         u.tx_q
129
130 /***********************Defines*****************************/
131      
132 #define DMA_ADDR_INIT(_eng)     {   \
133     .base = DMA_BASE_OFF_HST,       \
134     .eng  = DMA_ENG_OFF_##_eng      \
135 }
136 /**
137  * @brief check if the val doesn't lie between the low & high of
138  *        the engine numbers
139  */
140 #define DMA_ENG_CHECK(_val, _low, _high)    \
141     ((_val) < DMA_ENGINE_##_low || (_val) > DMA_ENGINE_##_high)
142     
143
144 /********************************Globals*************************************/
145
146 __dma_eng_q_t    eng_q[DMA_ENGINE_MAX] = {
147     {.addr = DMA_ADDR_INIT(RX0)},
148     {.addr = DMA_ADDR_INIT(RX1)},
149     {.addr = DMA_ADDR_INIT(RX2)},
150     {.addr = DMA_ADDR_INIT(RX3)},
151     {.addr = DMA_ADDR_INIT(TX0)},
152     {.addr = DMA_ADDR_INIT(TX1)},
153 };   
154
155 /**********************************API's*************************************/
156
157 /**
158  * @brief Read the register
159  * 
160  * @param addr
161  * 
162  * @return A_UINT32
163  */
164 A_UINT32
165 __dma_reg_read(A_UINT32 addr)
166 {
167     return *((volatile A_UINT32 *)addr);
168 }
169 /**
170  * @brief Write into the register
171  * 
172  * @param addr
173  * @param val
174  */
175 void
176 __dma_reg_write(A_UINT32 addr, A_UINT32 val)
177 {
178     *((volatile A_UINT32 *)addr) = val;
179 }
180 /**
181  * @brief Set the base address
182  * 
183  * @param eng_no
184  * @param if_type
185  */
186 void
187 __dma_set_base(dma_engine_t  eng_no, dma_iftype_t if_type)
188 {
189     switch (if_type) {
190     case DMA_IF_GMAC:
191         eng_q[eng_no].addr.base = DMA_BASE_OFF_GMAC;
192         break;
193     case DMA_IF_PCI:
194         eng_q[eng_no].addr.base = DMA_BASE_OFF_PCI;
195         break;
196     case DMA_IF_PCIE:
197         eng_q[eng_no].addr.base = DMA_BASE_OFF_PCIE;
198         break;
199     default:
200         return;
201     }
202 }
203 /**
204  * @brief init the Transmit queue
205  * 
206  * @param eng_no
207  * @param if_type
208  * 
209  * @return A_UINT16
210  */
211 A_UINT16
212 __dma_lib_tx_init(dma_engine_t  eng_no, dma_iftype_t  if_type)
213 {
214     __dma_desc_t  *head = NULL;
215     A_UINT32     addr;
216
217     if(DMA_ENG_CHECK(eng_no, TX0, TX1))
218         return 1;
219
220     DMA_Engine_init_tx_queue(&eng_q[eng_no].txq);
221
222     __dma_set_base(eng_no, if_type); 
223
224     addr  = eng_q[eng_no].addr.base + eng_q[eng_no].addr.eng;
225
226     head = eng_q[eng_no].txq.head;
227
228     __dma_reg_write(addr + DMA_REG_TXDESC,(A_UINT32)head);
229     __dma_reg_write(addr + DMA_REG_TXBURST, DMA_BURST_16W);
230     __dma_reg_write(addr + DMA_REG_TXSWAP, DMA_BYTE_SWAP_ON);
231
232     return 0;
233 }
234
235 void
236 __dma_lib_rx_config(dma_engine_t   eng_no, A_UINT16   num_desc, 
237                     A_UINT16     gran)
238 {
239     __dma_desc_t     *desc = NULL;
240     A_UINT32       addr = 0;
241
242     /**
243      * Allocate the Receive Queue
244      */
245     DMA_Engine_config_rx_queue(&eng_q[eng_no].rxq, num_desc, gran);
246
247     desc  = eng_q[eng_no].rxq.head;
248     addr  = eng_q[eng_no].addr.base + eng_q[eng_no].addr.eng;
249     /**
250      * Update RX queue head in the H/W, set the burst & say go
251      */
252     __dma_reg_write(addr + DMA_REG_RXDESC, (A_UINT32)desc);
253     __dma_reg_write(addr + DMA_REG_RXBURST, DMA_BURST_8W);
254     __dma_reg_write(addr + DMA_REG_RXSWAP,  DMA_BYTE_SWAP_ON);
255     __dma_reg_write(addr + DMA_REG_RXSTART, DMA_BIT_SET);
256
257 }
258     
259 /**
260  * @brief Initialize the DMA engine
261  * 
262  * @param rx_desc
263  * 
264  * @return A_UINT16
265  */
266 A_UINT16 
267 __dma_lib_rx_init(dma_engine_t   eng_no, dma_iftype_t     if_type)
268 {
269     if(DMA_ENG_CHECK(eng_no, RX0, RX3))
270         return 1;
271
272     /**
273      * XXX:The init can be called multiple times to setup different
274      * geometries of descriptors
275      */
276     DMA_Engine_init_rx_queue(&eng_q[eng_no].rxq);
277
278     __dma_set_base(eng_no, if_type);
279     
280     return 0;
281 }
282 /**
283  * @brief Transmit VBUF for the specified engine number
284  * 
285  * @param VBUF
286  * 
287  * @return A_UINT16
288  */
289 A_UINT16      
290 __dma_hard_xmit(dma_engine_t eng_no, VBUF *vbuf)
291 {
292     A_UINT32 addr;
293
294     addr = eng_q[eng_no].addr.base + eng_q[eng_no].addr.eng;
295
296     DMA_Engine_xmit_buf(&eng_q[eng_no].txq, vbuf);
297     /**
298      * Say go
299      */
300     __dma_reg_write(addr + DMA_REG_TXSTART, DMA_BIT_SET);
301 }
302 /**
303  * @brief return a VBUF for the specified engine number
304  * 
305  * @param eng_no
306  * 
307  * @return VBUF*
308  */
309 VBUF *
310 __dma_reap_xmitted(dma_engine_t eng_no)
311 {
312     return DMA_Engine_reap_xmited_buf(&eng_q[eng_no].txq);
313 }
314 /**
315  * @brief flush all xmitted & to be xmitted (if you have the
316  *        window) dudes from H/W
317  * 
318  * @param eng_no
319  */
320 void            
321 __dma_flush_xmit(dma_engine_t  eng_no)
322 {
323     A_UINT32 addr;
324     __dma_desc_t  *desc, *term;
325
326     addr = eng_q[eng_no].addr.base + eng_q[eng_no].addr.eng;
327
328     desc = eng_q[eng_no].txq.head;
329     term = eng_q[eng_no].txq.terminator;
330
331     /**
332      * XXX: I don't know how to kick the all dudes out, Ideally
333      * there should be a DMA reset button (the red one)
334      */
335     __dma_reg_write(addr + DMA_REG_TXSTART, DMA_BIT_CLEAR);
336     __dma_reg_write(addr + DMA_REG_TXDESC,(A_UINT32)term);
337
338     /**
339      * Make the H/W queue ready for TX reap
340      */
341     for(;desc != term; desc = desc->nextAddr)
342         desc->status = DMA_STATUS_OWN_DRV;
343
344 //    DMA_Engine_flush_xmit(&eng_q[eng_no].txq);
345 }
346 /**
347  * @brief check if there are xmitted vbufs (dudes) hanging
348  *        around
349  * 
350  * @param eng_no
351  * 
352  * @return A_UINT16
353  */
354 A_UINT16
355 __dma_xmit_done(dma_engine_t  eng_no)
356 {
357     if(DMA_ENG_CHECK(eng_no, TX0, TX1))
358         return 0;
359
360     return DMA_Engine_has_compl_packets(&eng_q[eng_no].txq);        
361 }
362 /**
363  * @brief Reap VBUF's from the specified engine number
364  * 
365  * @param eng
366  * 
367  * @return VBUF*
368  */
369 VBUF *
370 __dma_reap_recv(dma_engine_t  eng)
371 {
372     return DMA_Engine_reap_recv_buf(&eng_q[eng].rxq);
373 }
374 /**
375  * @brief return to source, put the vbuf back into the queue, In
376  *        case the Engine is stopped so start it again
377  * 
378  * @param eng_no
379  * @param vbuf
380  */
381 void
382 __dma_return_recv(dma_engine_t  eng_no, VBUF *vbuf)
383 {
384     A_UINT32 addr;
385
386     addr = eng_q[eng_no].addr.base + eng_q[eng_no].addr.eng;
387
388     DMA_Engine_return_recv_buf(&eng_q[eng_no].rxq, vbuf);
389
390     __dma_reg_write(addr + DMA_REG_RXSTART, DMA_BIT_SET);
391 }
392 /**
393  * @brief check if there are freshly arrived vbufs (dudes)
394  * 
395  * @param eng_no
396  * 
397  * @return A_UINT16
398  */
399 A_UINT16
400 __dma_recv_pkt(dma_engine_t  eng_no)
401 {
402     if(DMA_ENG_CHECK(eng_no, RX0, RX3))
403         return 0;
404
405     return DMA_Engine_has_compl_packets(&eng_q[eng_no].rxq);        
406 }
407
408 void
409 dma_lib_module_install(struct dma_lib_api  *apis)
410 {
411     apis->tx_init      = __dma_lib_tx_init;
412     apis->rx_init      = __dma_lib_rx_init;
413     apis->rx_config    = __dma_lib_rx_config;
414     apis->hard_xmit    = __dma_hard_xmit;
415     apis->flush_xmit   = __dma_flush_xmit;
416     apis->xmit_done    = __dma_xmit_done;
417     apis->reap_recv    = __dma_reap_recv;
418     apis->reap_xmitted = __dma_reap_xmitted;
419     apis->return_recv  = __dma_return_recv;
420     apis->recv_pkt     = __dma_recv_pkt;
421 }