1 /* Calypso DBB internal UART Driver */
3 /* (C) 2010 by Harald Welte <laforge@gnumonks.org>
4 * (C) 2010 by Ingo Albrecht <prom@berlin.ccc.de>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
32 #include <comm/sercomm.h>
34 #include <calypso/irq.h>
35 #include <calypso/uart.h>
37 #define BASE_ADDR_UART_MODEM 0xffff5000
38 #define OFFSET_IRDA 0x800
40 #define UART_REG(n,m) (BASE_ADDR_UART_MODEM + ((n)*OFFSET_IRDA)+(m))
45 #define REG_OFFS(m) ((m) &= ~(LCR7BIT|LCRBFBIT|MCR6BIT))
46 /* read access LCR[7] = 0 */
67 /* read access LCR[7] = 1 */
70 DIV1_6 = ACREG | LCR7BIT,
71 /* read/write access LCR[7:0] = 0xbf */
73 XON1 = MCR | LCRBFBIT,
74 XON2 = LSR | LCRBFBIT,
75 XOFF1 = MSR | LCRBFBIT,
76 XOFF2 = SPR | LCRBFBIT,
77 /* read/write access if EFR[4] = 1 and MCR[6] = 1 */
81 /* write access LCR[7] = 0 */
83 #define FCR IIR /* only if EFR[4] = 1 */
91 RX_FIFO_CLEAR = (1 << 1),
92 TX_FIFO_CLEAR = (1 << 2),
95 #define TX_FIFO_TRIG_SHIFT 4
96 #define RX_FIFO_TRIG_SHIFT 6
99 IIR_INT_PENDING = 0x01,
101 IIR_INT_TYPE_RX_STATUS_ERROR = 0x06,
102 IIR_INT_TYPE_RX_TIMEOUT = 0x0C,
103 IIR_INT_TYPE_RHR = 0x04,
104 IIR_INT_TYPE_THR = 0x02,
105 IIR_INT_TYPE_MSR = 0x00,
106 IIR_INT_TYPE_XOFF = 0x10,
107 IIR_INT_TYPE_FLOW = 0x20,
108 IIR_FCR0_MIRROR = 0xC0,
111 #define UART_REG_UIR 0xffff6000
113 /* enable or disable the divisor latch for access to DLL, DLH */
114 static void uart_set_lcr7bit(int uart, int on)
118 reg = readb(UART_REG(uart, LCR));
123 writeb(reg, UART_REG(uart, LCR));
126 static uint8_t old_lcr;
127 static void uart_set_lcr_bf(int uart, int on)
129 old_lcr = readb(UART_REG(uart, LCR));
132 writeb(0xBF, UART_REG(uart, LCR));
134 writeb(old_lcr, UART_REG(uart, LCR));
137 /* Enable or disable the TCR_TLR latch bit in MCR[6] */
138 static void uart_set_mcr6bit(int uart, int on)
141 /* we assume EFR[4] is always set to 1 */
142 mcr = readb(UART_REG(uart, MCR));
147 writeb(mcr, UART_REG(uart, MCR));
150 static void uart_reg_write(int uart, enum uart_reg reg, uint8_t val)
153 uart_set_lcr_bf(uart, 1);
154 else if (reg & LCR7BIT)
155 uart_set_lcr7bit(uart, 1);
156 else if (reg & MCR6BIT)
157 uart_set_mcr6bit(uart, 1);
159 writeb(val, UART_REG(uart, REG_OFFS(reg)));
162 uart_set_lcr_bf(uart, 0);
163 else if (reg & LCR7BIT)
164 uart_set_lcr7bit(uart, 0);
165 else if (reg & MCR6BIT)
166 uart_set_mcr6bit(uart, 0);
169 /* read from a UART register, applying any required latch bits */
170 static uint8_t uart_reg_read(int uart, enum uart_reg reg)
175 uart_set_lcr_bf(uart, 1);
176 else if (reg & LCR7BIT)
177 uart_set_lcr7bit(uart, 1);
178 else if (reg & MCR6BIT)
179 uart_set_mcr6bit(uart, 1);
181 ret = readb(UART_REG(uart, REG_OFFS(reg)));
184 uart_set_lcr_bf(uart, 0);
185 else if (reg & LCR7BIT)
186 uart_set_lcr7bit(uart, 0);
187 else if (reg & MCR6BIT)
188 uart_set_mcr6bit(uart, 0);
193 static void uart_irq_handler_cons(enum irq_nr irq)
195 const uint8_t uart = CONS_UART_NR;
198 //uart_putchar_nb(uart, 'U');
200 iir = uart_reg_read(uart, IIR);
201 if (iir & IIR_INT_PENDING)
204 switch (iir & IIR_INT_TYPE) {
205 case IIR_INT_TYPE_RHR:
207 case IIR_INT_TYPE_THR:
208 if (cons_rb_flush() == 1) {
209 /* everything was flushed, disable THR IRQ */
210 uint8_t ier = uart_reg_read(uart, IER);
212 uart_reg_write(uart, IER, ier);
215 case IIR_INT_TYPE_MSR:
217 case IIR_INT_TYPE_RX_STATUS_ERROR:
219 case IIR_INT_TYPE_RX_TIMEOUT:
221 case IIR_INT_TYPE_XOFF:
226 static void uart_irq_handler_sercomm(enum irq_nr irq)
228 const uint8_t uart = SERCOMM_UART_NR;
231 //uart_putchar_nb(uart, 'U');
233 iir = uart_reg_read(uart, IIR);
234 if (iir & IIR_INT_PENDING)
237 switch (iir & IIR_INT_TYPE) {
238 case IIR_INT_TYPE_RX_TIMEOUT:
239 case IIR_INT_TYPE_RHR:
240 /* as long as we have rx data available */
241 while (uart_getchar_nb(uart, &ch)) {
242 if (sercomm_drv_rx_char(ch) < 0) {
243 /* sercomm cannot receive more data right now */
244 uart_irq_enable(uart, UART_IRQ_RX_CHAR, 0);
248 case IIR_INT_TYPE_THR:
249 /* as long as we have space in the FIFO */
250 while (!uart_tx_busy(uart)) {
251 /* get a byte from sercomm */
252 if (!sercomm_drv_pull(&ch)) {
253 /* no more bytes in sercomm, stop TX interrupts */
254 uart_irq_enable(uart, UART_IRQ_TX_EMPTY, 0);
257 /* write the byte into the TX FIFO */
258 uart_putchar_nb(uart, ch);
261 case IIR_INT_TYPE_MSR:
263 case IIR_INT_TYPE_RX_STATUS_ERROR:
265 case IIR_INT_TYPE_XOFF:
270 static const uint8_t uart2irq[] = {
272 [1] = IRQ_UART_MODEM,
275 void uart_init(uint8_t uart)
277 uint8_t irq = uart2irq[uart];
279 uart_reg_write(uart, IER, 0x00);
280 if (uart == CONS_UART_NR) {
282 irq_register_handler(irq, &uart_irq_handler_cons);
283 irq_config(irq, 0, 0, 0xff);
287 irq_register_handler(irq, &uart_irq_handler_sercomm);
288 irq_config(irq, 0, 0, 0xff);
290 uart_irq_enable(uart, UART_IRQ_RX_CHAR, 1);
294 /* assign UART to MCU and unmask interrupts*/
295 writeb(UART_REG_UIR, 0x00);
298 /* select UART mode */
299 uart_reg_write(uart, MDR1, 0);
300 /* no XON/XOFF flow control, ENHANCED_EN, no auto-RTS/CTS */
301 uart_reg_write(uart, EFR, (1 << 4));
302 /* enable Tx/Rx FIFO, Tx trigger at 56 spaces, Rx trigger at 60 chars */
303 uart_reg_write(uart, FCR, FIFO_EN | RX_FIFO_CLEAR | TX_FIFO_CLEAR |
304 (3 << TX_FIFO_TRIG_SHIFT) | (3 << RX_FIFO_TRIG_SHIFT));
306 /* THR interrupt only when TX FIFO and TX shift register are empty */
307 uart_reg_write(uart, SCR, (1 << 0));// | (1 << 3));
309 /* 8 bit, 1 stop bit, no parity, no break */
310 uart_reg_write(uart, LCR, 0x03);
312 uart_set_lcr7bit(uart, 0);
315 void uart_irq_enable(uint8_t uart, enum uart_irq irq, int on)
317 uint8_t ier = uart_reg_read(uart, IER);
321 case UART_IRQ_TX_EMPTY:
324 case UART_IRQ_RX_CHAR:
334 uart_reg_write(uart, IER, ier);
338 void uart_putchar_wait(uint8_t uart, int c)
340 /* wait while TX FIFO indicates full */
341 while (readb(UART_REG(uart, SSR)) & 0x01) { }
343 /* put character in TX FIFO */
344 writeb(c, UART_REG(uart, THR));
347 int uart_putchar_nb(uint8_t uart, int c)
349 /* if TX FIFO indicates full, abort */
350 if (readb(UART_REG(uart, SSR)) & 0x01)
353 writeb(c, UART_REG(uart, THR));
357 int uart_getchar_nb(uint8_t uart, uint8_t *ch)
359 if (!(readb(UART_REG(uart, LSR)) & 0x01))
362 *ch = readb(UART_REG(uart, RHR));
366 int uart_tx_busy(uint8_t uart)
368 if (readb(UART_REG(uart, SSR)) & 0x01)
373 static const uint16_t divider[] = {
374 [UART_38400] = 21, /* 38,690 */
375 [UART_57600] = 14, /* 58,035 */
376 [UART_115200] = 7, /* 116,071 */
377 [UART_230400] = 4, /* 203,125! (-3% would be 223,488) */
378 [UART_460800] = 2, /* 406,250! (-3% would be 446,976) */
379 [UART_921600] = 1, /* 812,500! (-3% would be 893,952) */
382 int uart_baudrate(uint8_t uart, enum uart_baudrate bdrt)
386 if (bdrt > ARRAY_SIZE(divider))
390 uart_set_lcr7bit(uart, 1);
391 writeb(div & 0xff, UART_REG(uart, DLL));
392 writeb(div >> 8, UART_REG(uart, DLH));
393 uart_set_lcr7bit(uart, 0);