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