iPXE
uart.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  *
19  * You can also choose to distribute this program under the terms of
20  * the Unmodified Binary Distribution Licence (as given in the file
21  * COPYING.UBDL), provided that you have satisfied its requirements.
22  */
23 
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25 
26 /** @file
27  *
28  * 16550-compatible UART
29  *
30  */
31 
32 #include <unistd.h>
33 #include <errno.h>
34 #include <ipxe/uart.h>
35 
36 /** Timeout for transmit holding register to become empty */
37 #define UART_THRE_TIMEOUT_MS 100
38 
39 /** Timeout for transmitter to become empty */
40 #define UART_TEMT_TIMEOUT_MS 1000
41 
42 /**
43  * Transmit data
44  *
45  * @v uart UART
46  * @v data Data
47  */
48 void uart_transmit ( struct uart *uart, uint8_t data ) {
49  unsigned int i;
50  uint8_t lsr;
51 
52  /* Wait for transmitter holding register to become empty */
53  for ( i = 0 ; i < UART_THRE_TIMEOUT_MS ; i++ ) {
54  lsr = uart_read ( uart, UART_LSR );
55  if ( lsr & UART_LSR_THRE )
56  break;
57  mdelay ( 1 );
58  }
59 
60  /* Transmit data (even if we timed out) */
62 }
63 
64 /**
65  * Flush data
66  *
67  * @v uart UART
68  */
69 void uart_flush ( struct uart *uart ) {
70  unsigned int i;
71  uint8_t lsr;
72 
73  /* Wait for transmitter and receiver to become empty */
74  for ( i = 0 ; i < UART_TEMT_TIMEOUT_MS ; i++ ) {
75  uart_read ( uart, UART_RBR );
76  lsr = uart_read ( uart, UART_LSR );
77  if ( ( lsr & UART_LSR_TEMT ) && ! ( lsr & UART_LSR_DR ) )
78  break;
79  }
80 }
81 
82 /**
83  * Check for existence of UART
84  *
85  * @v uart UART
86  * @ret rc Return status code
87  */
88 int uart_exists ( struct uart *uart ) {
89 
90  /* Fail if no UART port is defined */
91  if ( ! uart->base )
92  return -ENODEV;
93 
94  /* Fail if UART scratch register seems not to be present */
95  uart_write ( uart, UART_SCR, 0x18 );
96  if ( uart_read ( uart, UART_SCR ) != 0x18 )
97  return -ENODEV;
98  uart_write ( uart, UART_SCR, 0xae );
99  if ( uart_read ( uart, UART_SCR ) != 0xae )
100  return -ENODEV;
101 
102  return 0;
103 }
104 
105 /**
106  * Initialise UART
107  *
108  * @v uart UART
109  * @v baud Baud rate, or zero to leave unchanged
110  * @v lcr Line control register value, or zero to leave unchanged
111  * @ret rc Return status code
112  */
113 int uart_init ( struct uart *uart, unsigned int baud, uint8_t lcr ) {
114  uint8_t dlm;
115  uint8_t dll;
116  int rc;
117 
118  /* Check for existence of UART */
119  if ( ( rc = uart_exists ( uart ) ) != 0 )
120  return rc;
121 
122  /* Configure divisor and line control register, if applicable */
123  if ( ! lcr )
124  lcr = uart_read ( uart, UART_LCR );
125  uart->lcr = lcr;
126  uart_write ( uart, UART_LCR, ( lcr | UART_LCR_DLAB ) );
127  if ( baud ) {
128  uart->divisor = ( UART_MAX_BAUD / baud );
129  dlm = ( ( uart->divisor >> 8 ) & 0xff );
130  dll = ( ( uart->divisor >> 0 ) & 0xff );
131  uart_write ( uart, UART_DLM, dlm );
132  uart_write ( uart, UART_DLL, dll );
133  } else {
134  dlm = uart_read ( uart, UART_DLM );
135  dll = uart_read ( uart, UART_DLL );
136  uart->divisor = ( ( dlm << 8 ) | dll );
137  }
138  uart_write ( uart, UART_LCR, ( lcr & ~UART_LCR_DLAB ) );
139 
140  /* Disable interrupts */
141  uart_write ( uart, UART_IER, 0 );
142 
143  /* Enable FIFOs */
145 
146  /* Assert DTR and RTS */
148 
149  /* Flush any stale data */
150  uart_flush ( uart );
151 
152  return 0;
153 }
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
void uart_flush(struct uart *uart)
Flush data.
Definition: uart.c:69
int uart_exists(struct uart *uart)
Check for existence of UART.
Definition: uart.c:88
uint16_t divisor
Baud rate divisor.
Definition: uart.h:84
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
Error codes.
A 16550-compatible UART.
Definition: uart.h:80
#define UART_LSR
Line status register.
Definition: uart.h:62
void uart_transmit(struct uart *uart, uint8_t data)
Transmit data.
Definition: uart.c:48
uint8_t lcr
Line control register.
Definition: uart.h:86
void * base
I/O port base address.
Definition: uart.h:82
int uart_init(struct uart *uart, unsigned int baud, uint8_t lcr)
Initialise UART.
Definition: uart.c:113
#define UART_DLL
Divisor latch (least significant byte)
Definition: uart.h:71
#define UART_LSR_THRE
Transmitter holding register empty.
Definition: uart.h:64
#define UART_MAX_BAUD
Maximum baud rate.
Definition: uart.h:77
#define UART_THR
Transmitter holding register.
Definition: uart.h:15
#define UART_RBR
Receiver buffer register.
Definition: uart.h:18
#define UART_DLM
Divisor latch (most significant byte)
Definition: uart.h:74
void uart_write(struct uart *uart, unsigned int addr, uint8_t data)
uint8_t uart_read(struct uart *uart, unsigned int addr)
#define ENODEV
No such device.
Definition: errno.h:509
unsigned char uint8_t
Definition: stdint.h:10
#define UART_FCR
FIFO control register.
Definition: uart.h:24
#define UART_SCR
Scratch register.
Definition: uart.h:68
#define UART_LSR_TEMT
Transmitter empty.
Definition: uart.h:65
#define UART_THRE_TIMEOUT_MS
Timeout for transmit holding register to become empty.
Definition: uart.c:37
16550-compatible UART
#define UART_MCR
Modem control register.
Definition: uart.h:57
#define UART_IER
Interrupt enable register.
Definition: uart.h:21
void mdelay(unsigned long msecs)
Delay for a fixed number of milliseconds.
Definition: timer.c:78
#define UART_TEMT_TIMEOUT_MS
Timeout for transmitter to become empty.
Definition: uart.c:40
#define UART_MCR_RTS
Request to send.
Definition: uart.h:59
uint8_t data[48]
Additional event data.
Definition: ena.h:22
#define UART_LCR
Line control register.
Definition: uart.h:28
#define UART_FCR_FE
FIFO enable.
Definition: uart.h:25
#define UART_MCR_DTR
Data terminal ready.
Definition: uart.h:58
#define UART_LCR_DLAB
Divisor latch access bit.
Definition: uart.h:34
#define UART_LSR_DR
Data ready.
Definition: uart.h:63