2 * Copyright (c) 2013 Qualcomm Atheros, Inc.
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:
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
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
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.
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.
36 * $Id: //depot/sw/branches/fusion_usb/target_firmware/magpie_fw_dev/build/magpie_1_1/sboot/cmnos/uart/src/uart_api.c#1 $
38 * This file contains UART functions
42 #if SYSTEM_MODULE_UART
44 #include "athos_api.h"
46 //static global control block
48 static struct uart_blk uart_ctl_blk;
50 static void _uart_hwinit(uint32_t freq, uint32_t baud);
58 /*! Initialize UART hardware */
61 /* Disable port interrupts while changing hardware */
62 UART_REG_WRITE(IER_OFFSET, 0);
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);
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);
73 /* Don't allow interrupts. */
74 UART_REG_WRITE(IER_OFFSET, 0);
77 * Enable and clear FIFO.
78 * We don't really use the FIFO for output, but it might still
79 * be useful for input.
81 UART_REG_WRITE(FCR_OFFSET,
83 FCR_RCVR_FIFO_RST_SET(1) |
84 FCR_XMIT_FIFO_RST_SET(1)));
86 /*! Initialize UART software buffer */
87 uart_ctl_blk._tx.start_index = 0;
88 uart_ctl_blk._tx.end_index = 0;
92 /*!- dummy put character
96 _uart_char_put_nothing(uint8_t ch)
102 /*!- dummy get character
106 _uart_char_get_nothing(uint8_t* ch)
108 return 0; //return FALSE;
116 _uart_char_put(uint8_t ch)
122 index = (uart_ctl_blk._tx.end_index+1) & (UART_FIFO_SIZE-1);
123 if(index == uart_ctl_blk._tx.start_index) {
126 index = (uart_ctl_blk._tx.end_index+1) & (UART_FIFO_SIZE-1);
127 if (index != uart_ctl_blk._tx.start_index) {
130 if (count++ > 100000) {
131 /*! If Tx buffer is full, uart_underrun_t++, return FALSE */
132 uart_ctl_blk._tx.overrun_err++;
137 uart_ctl_blk._tx.buf[uart_ctl_blk._tx.end_index] = ch;
138 uart_ctl_blk._tx.end_index = index;
140 /*! If Tx buffer is full, uart_underrun_t++, return FALSE */
144 for (i=0; i<UART_RETRY_COUNT; i++) {
145 lsr = UART_REG_READ(LSR_OFFSET);
146 if (lsr & LSR_THRE_MASK) {
151 /*! Now, the transmit buffer is empty, put to tx buffer */
152 UART_REG_WRITE(THR_OFFSET, ch);
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.
160 for (i=0; i<UART_RETRY_COUNT; i++) {
161 lsr = UART_REG_READ(LSR_OFFSET);
162 if (lsr & LSR_TEMT_MASK) {
174 _uart_char_put_nowait(uint8_t ch)
177 /*! If Tx buffer is full, uart_underrun_t++, return FALSE */
181 for (i=0; i<UART_RETRY_COUNT; i++) {
182 lsr = UART_REG_READ(LSR_OFFSET);
183 if (lsr & LSR_THRE_MASK) {
188 /*! Now, the transmit buffer is empty, put to tx buffer */
189 UART_REG_WRITE(THR_OFFSET, ch);
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.
197 for (i=0; i<UART_RETRY_COUNT; i++) {
198 lsr = UART_REG_READ(LSR_OFFSET);
199 if (lsr & LSR_TEMT_MASK) {
211 _uart_char_get(uint8_t* ch)
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)
217 *ch = UART_REG_READ(RBR_OFFSET);
220 /*! Else return FALSE */
235 volatile uint32_t lsr;
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
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);
263 return uart_ctl_blk._tx.overrun_err;
270 _uart_str_out(uint8_t* str)
274 if( !uart_ctl_blk.debug_mode )
277 while (str[i] != 0) {
278 _uart_char_put(str[i]);
284 /*!- enable or disable put/get
288 _uart_config(uint16_t flag)
290 if( uart_ctl_blk.debug_mode != flag )
292 uart_ctl_blk.debug_mode = !uart_ctl_blk.debug_mode;
295 if( uart_ctl_blk.debug_mode )
296 uart_ctl_blk._uart->_uart_char_put = _uart_char_put;
299 uart_ctl_blk._uart->_uart_char_put = _uart_char_put_nothing;
307 _uart_hwinit(uint32_t freq, uint32_t baud)
310 uint32_t baud_divisor = freq/16/baud;
312 _lcr = UART_REG_READ(LCR_OFFSET);
313 _lcr |= LCR_DLAB_SET(1);
314 UART_REG_WRITE(LCR_OFFSET, _lcr);
316 UART_REG_WRITE(DLH_OFFSET, baud_divisor >> 8);
317 UART_REG_WRITE(DLL_OFFSET, baud_divisor & 0xff);
319 _lcr &= ~LCR_DLAB_SET(1);
320 UART_REG_WRITE(LCR_OFFSET, _lcr);
323 /********** EXPORT function ***********/
325 /*!- Install the function table
328 void cmnos_uart_module_install(struct uart_api *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;
340 uart_ctl_blk._uart = apis;
341 uart_ctl_blk.debug_mode = TRUE;
345 #endif /* SYSTEM_MODULE_UART */