Setting up repository
[linux-libre-firmware.git] / ath9k_htc / sboot / magpie_1_1 / sboot / cmnos / uart / src / uart_api.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  * $Id: //depot/sw/branches/fusion_usb/target_firmware/magpie_fw_dev/build/magpie_1_1/sboot/cmnos/uart/src/uart_api.c#1 $
37  *
38  * This file contains UART functions
39  */
40 #include "sys_cfg.h"
41
42 #if SYSTEM_MODULE_UART
43
44 #include "athos_api.h"
45
46 //static global control block
47 //
48 static struct uart_blk uart_ctl_blk;    
49
50 static void _uart_hwinit(uint32_t freq, uint32_t baud);
51
52 /*!- Initialize UART
53  *
54  */
55 uint32_t
56 _uart_init(void)
57 {
58     /*! Initialize UART hardware */
59     uint32_t _lcr;
60
61     /* Disable port interrupts while changing hardware */
62     UART_REG_WRITE(IER_OFFSET, 0);
63
64     /* Set databits, stopbits and parity. */
65     _lcr = LCR_CLS_SET(3) | LCR_STOP_SET(0) | LCR_PEN_SET(0);
66     UART_REG_WRITE(LCR_OFFSET, _lcr);
67
68     /* Set baud rate. */
69     _uart_hwinit(A_REFCLK_SPEED_GET(), UART_DEFAULT_BAUD);
70 //    _uart_hwinit(A_REFCLK_SPEED_GET(), 115200);
71     //_uart_hwinit(SYSTEM_CLK, UART_DEFAULT_BAUD);
72
73     /* Don't allow interrupts. */
74     UART_REG_WRITE(IER_OFFSET, 0);
75
76     /*
77      * Enable and clear FIFO.
78      * We don't really use the FIFO for output, but it might still
79      * be useful for input.
80      */
81     UART_REG_WRITE(FCR_OFFSET,
82                     (FCR_FIFO_EN_SET(1) |
83                      FCR_RCVR_FIFO_RST_SET(1) |
84                      FCR_XMIT_FIFO_RST_SET(1)));
85
86     /*! Initialize UART software buffer */
87     uart_ctl_blk._tx.start_index = 0;
88     uart_ctl_blk._tx.end_index = 0;
89 }
90
91
92 /*!- dummy put character 
93  *
94  */
95 void
96 _uart_char_put_nothing(uint8_t ch)
97 {
98     // do nothing
99 }
100
101
102 /*!- dummy get character 
103  *
104  */
105 uint16_t
106 _uart_char_get_nothing(uint8_t* ch)
107 {
108     return 0;   //return FALSE;
109 }
110
111
112 /*!- Put a character 
113  *
114  */
115 void
116 _uart_char_put(uint8_t ch)
117 {
118 #if USE_POST_BUFFER
119     uint16_t index;
120     uint32_t count = 0; 
121
122     index = (uart_ctl_blk._tx.end_index+1) & (UART_FIFO_SIZE-1);
123         if(index == uart_ctl_blk._tx.start_index) {
124             while (1) {
125             _uart_task();
126             index = (uart_ctl_blk._tx.end_index+1) & (UART_FIFO_SIZE-1);
127                 if (index != uart_ctl_blk._tx.start_index) {
128                     break;
129             }
130             if (count++ > 100000) {
131                 /*! If Tx buffer is full, uart_underrun_t++, return FALSE */
132                         uart_ctl_blk._tx.overrun_err++;
133                         return;
134             }
135             }
136         }
137     uart_ctl_blk._tx.buf[uart_ctl_blk._tx.end_index] = ch;
138     uart_ctl_blk._tx.end_index = index;
139 #else
140     /*! If Tx buffer is full, uart_underrun_t++, return FALSE */
141     uint32_t lsr;
142     int i;
143
144     for (i=0; i<UART_RETRY_COUNT; i++) {
145         lsr = UART_REG_READ(LSR_OFFSET);
146         if (lsr & LSR_THRE_MASK) {
147             break;
148         }
149     } 
150
151     /*! Now, the transmit buffer is empty, put to tx buffer */
152     UART_REG_WRITE(THR_OFFSET, ch);
153
154     /*
155      * Hang around until the character has been safely sent.
156      * If we don't do this, the system could go to sleep, which
157      * causes the UART's clock to stop, and we won't see output
158      * that's stuck in the FIFO.
159      */
160     for (i=0; i<UART_RETRY_COUNT; i++) {
161         lsr = UART_REG_READ(LSR_OFFSET);
162         if (lsr & LSR_TEMT_MASK) {
163             break;
164         }
165     }
166 #endif
167
168 }
169
170 /*!- Put a character 
171  *
172  */
173 void
174 _uart_char_put_nowait(uint8_t ch)
175 {
176
177     /*! If Tx buffer is full, uart_underrun_t++, return FALSE */
178     uint32_t lsr;
179     int i;
180
181     for (i=0; i<UART_RETRY_COUNT; i++) {
182         lsr = UART_REG_READ(LSR_OFFSET);
183         if (lsr & LSR_THRE_MASK) {
184             break;
185         }
186     } 
187
188     /*! Now, the transmit buffer is empty, put to tx buffer */
189     UART_REG_WRITE(THR_OFFSET, ch);
190
191     /*
192      * Hang around until the character has been safely sent.
193      * If we don't do this, the system could go to sleep, which
194      * causes the UART's clock to stop, and we won't see output
195      * that's stuck in the FIFO.
196      */
197     for (i=0; i<UART_RETRY_COUNT; i++) {
198         lsr = UART_REG_READ(LSR_OFFSET);
199         if (lsr & LSR_TEMT_MASK) {
200             break;
201         }
202     }
203
204 }
205
206
207 /*!- Get a character 
208  *
209  */
210 uint16_t
211 _uart_char_get(uint8_t* ch)
212 {
213
214     /*! If Rx FIFO is not empty, get char from Rx buffer, reutnr TRUE */
215     if ((UART_REG_READ(LSR_OFFSET) & LSR_DR_MASK) != 0) 
216     {
217         *ch = UART_REG_READ(RBR_OFFSET);
218         return 1;
219     }
220     /*! Else return FALSE */
221     else 
222     { 
223         return 0;
224     }
225 }
226
227 /*!- UART task 
228  *
229  */
230 void
231 _uart_task(void)
232 {
233 #if USE_POST_BUFFER
234     uint16_t count;
235     volatile uint32_t lsr;
236
237     /*! If Tx FIFO almost empty, move chars from Tx buffer to Tx FIFO */
238     lsr = UART_REG_READ(LSR_OFFSET);
239     if ((lsr & LSR_THRE_MASK) != 0) { //Transmitter holding register empty
240         count = 0;
241         while (count<16) {
242             if (uart_ctl_blk._tx.start_index != uart_ctl_blk._tx.end_index) {
243                 UART_REG_WRITE(THR_OFFSET, uart_ctl_blk._tx.buf[uart_ctl_blk._tx.start_index]);
244                 uart_ctl_blk._tx.start_index = (uart_ctl_blk._tx.start_index+1)
245                     & (UART_FIFO_SIZE-1);
246             }
247             else
248             {
249                 break;
250             }
251             count++;
252         }
253     }
254 #endif
255     return;
256 }
257
258
259
260  uint32_t 
261 _uart_status()
262 {
263         return uart_ctl_blk._tx.overrun_err;
264 }
265
266 /*!- Output a string 
267  *
268  */
269 void
270 _uart_str_out(uint8_t* str)
271 {
272     uint32_t i = 0;
273
274     if( !uart_ctl_blk.debug_mode )
275         return;
276
277     while (str[i] != 0) {
278         _uart_char_put(str[i]);
279         i++;
280     }
281     return;
282 }
283
284 /*!- enable or disable put/get
285  *
286  */
287 void
288 _uart_config(uint16_t flag)
289 {    
290     if( uart_ctl_blk.debug_mode != flag )
291     {
292         uart_ctl_blk.debug_mode = !uart_ctl_blk.debug_mode;
293         
294         // debug mode enable
295         if( uart_ctl_blk.debug_mode ) 
296             uart_ctl_blk._uart->_uart_char_put = _uart_char_put;
297         else
298             // debug mode enable
299             uart_ctl_blk._uart->_uart_char_put = _uart_char_put_nothing;
300     }
301 }
302
303 /*!- Set baudrate 
304  *
305  */
306 void
307 _uart_hwinit(uint32_t freq, uint32_t baud)
308 {
309     uint32_t _lcr;
310     uint32_t baud_divisor = freq/16/baud;
311
312     _lcr = UART_REG_READ(LCR_OFFSET);
313     _lcr |= LCR_DLAB_SET(1);
314     UART_REG_WRITE(LCR_OFFSET, _lcr);
315
316     UART_REG_WRITE(DLH_OFFSET, baud_divisor >> 8);
317     UART_REG_WRITE(DLL_OFFSET, baud_divisor & 0xff);
318
319     _lcr &= ~LCR_DLAB_SET(1);
320     UART_REG_WRITE(LCR_OFFSET, _lcr);
321 }
322
323 /********** EXPORT function ***********/
324
325 /*!- Install the function table 
326  *
327  */
328 void cmnos_uart_module_install(struct uart_api *apis)
329 {    
330     /* hook in APIs */
331     apis->_uart_init = _uart_init;
332     apis->_uart_char_put = _uart_char_put;
333     apis->_uart_char_get = _uart_char_get;
334     apis->_uart_str_out = _uart_str_out;
335     apis->_uart_task = _uart_task;
336     apis->_uart_config = _uart_config;
337     apis->_uart_status = _uart_status;
338     apis->_uart_hwinit = _uart_hwinit;
339
340     uart_ctl_blk._uart = apis;
341     uart_ctl_blk.debug_mode = TRUE;
342     return;
343 }
344
345 #endif /* SYSTEM_MODULE_UART */
346