1 /* This file is part of the coreboot project. */
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
15 #include <console/uart.h>
16 #include <device/mmio.h>
17 #include <boot/coreboot_tables.h>
18 #include <cpu/ti/am335x/uart.h>
20 #define EFR_ENHANCED_EN (1 << 4)
21 #define FCR_FIFO_EN (1 << 0)
22 #define MCR_TCR_TLR (1 << 6)
23 #define SYSC_SOFTRESET (1 << 1)
24 #define SYSS_RESETDONE (1 << 0)
26 #define LSR_RXFIFOE (1 << 0)
27 #define LSR_TXFIFOE (1 << 5)
30 * Initialise the serial port with the given baudrate divisor. The settings
31 * are always 8 data bits, no parity, 1 stop bit, no start bits.
33 static void am335x_uart_init(struct am335x_uart
*uart
, uint16_t div
)
35 uint16_t lcr_orig
, efr_orig
, mcr_orig
;
38 write16(&uart
->sysc
, uart
->sysc
| SYSC_SOFTRESET
);
39 while (!(read16(&uart
->syss
) & SYSS_RESETDONE
))
42 /* 1. switch to register config mode B */
43 lcr_orig
= read16(&uart
->lcr
);
44 write16(&uart
->lcr
, 0xbf);
47 * 2. Set EFR ENHANCED_EN bit. To access this bit, registers must
48 * be in TCR_TLR submode, meaning EFR[4] = 1 and MCR[6] = 1.
50 efr_orig
= read16(&uart
->efr
);
51 write16(&uart
->efr
, efr_orig
| EFR_ENHANCED_EN
);
53 /* 3. Switch to register config mode A */
54 write16(&uart
->lcr
, 0x80);
56 /* 4. Enable register submode TCR_TLR to access the UARTi.UART_TLR */
57 mcr_orig
= read16(&uart
->mcr
);
58 write16(&uart
->mcr
, mcr_orig
| MCR_TCR_TLR
);
60 /* 5. Enable the FIFO. For now we'll ignore FIFO triggers and DMA */
61 write16(&uart
->fcr
, FCR_FIFO_EN
);
63 /* 6. Switch to configuration mode B */
64 write16(&uart
->lcr
, 0xbf);
65 /* Skip steps 7 and 8 (setting up FIFO triggers for DMA) */
67 /* 9. Restore original EFR value */
68 write16(&uart
->efr
, efr_orig
);
70 /* 10. Switch to config mode A */
71 write16(&uart
->lcr
, 0x80);
73 /* 11. Restore original MCR value */
74 write16(&uart
->mcr
, mcr_orig
);
76 /* 12. Restore original LCR value */
77 write16(&uart
->lcr
, lcr_orig
);
79 /* Protocol, baud rate and interrupt settings */
81 /* 1. Disable UART access to DLL and DLH registers */
82 write16(&uart
->mdr1
, read16(&uart
->mdr1
) | 0x7);
84 /* 2. Switch to config mode B */
85 write16(&uart
->lcr
, 0xbf);
87 /* 3. Enable access to IER[7:4] */
88 write16(&uart
->efr
, efr_orig
| EFR_ENHANCED_EN
);
90 /* 4. Switch to operational mode */
91 write16(&uart
->lcr
, 0x0);
94 write16(&uart
->ier
, 0x0);
96 /* 6. Switch to config mode B */
97 write16(&uart
->lcr
, 0xbf);
99 /* 7. Set dll and dlh to the desired values (table 19-25) */
100 write16(&uart
->dlh
, (div
>> 8));
101 write16(&uart
->dll
, (div
& 0xff));
103 /* 8. Switch to operational mode to access ier */
104 write16(&uart
->lcr
, 0x0);
106 /* 9. Clear ier to disable all interrupts */
107 write16(&uart
->ier
, 0x0);
109 /* 10. Switch to config mode B */
110 write16(&uart
->lcr
, 0xbf);
112 /* 11. Restore efr */
113 write16(&uart
->efr
, efr_orig
);
115 /* 12. Set protocol formatting 8n1 (8 bit data, no parity, 1 stop bit) */
116 write16(&uart
->lcr
, 0x3);
118 /* 13. Load the new UART mode */
119 write16(&uart
->mdr1
, 0x0);
123 * Read a single byte from the serial port. Returns 1 on success, 0
124 * otherwise. When the function is successful, the character read is
125 * written into its argument c.
127 static unsigned char am335x_uart_rx_byte(struct am335x_uart
*uart
)
129 while (!(read16(&uart
->lsr
) & LSR_RXFIFOE
));
131 return read8(&uart
->rhr
);
135 * Output a single byte to the serial port.
137 static void am335x_uart_tx_byte(struct am335x_uart
*uart
, unsigned char data
)
139 while (!(read16(&uart
->lsr
) & LSR_TXFIFOE
));
141 return write8(&uart
->thr
, data
);
144 unsigned int uart_platform_refclk(void)
149 uintptr_t uart_platform_base(int idx
)
151 const unsigned int bases
[] = {
152 0x44e09000, 0x48022000, 0x48024000,
153 0x481a6000, 0x481a8000, 0x481aa000
155 if (idx
< ARRAY_SIZE(bases
))
160 void uart_init(int idx
)
162 struct am335x_uart
*uart
= uart_platform_baseptr(idx
);
163 uint16_t div
= (uint16_t) uart_baudrate_divisor(
164 get_uart_baudrate(), uart_platform_refclk(), 16);
165 am335x_uart_init(uart
, div
);
168 unsigned char uart_rx_byte(int idx
)
170 struct am335x_uart
*uart
= uart_platform_baseptr(idx
);
171 return am335x_uart_rx_byte(uart
);
174 void uart_tx_byte(int idx
, unsigned char data
)
176 struct am335x_uart
*uart
= uart_platform_baseptr(idx
);
177 am335x_uart_tx_byte(uart
, data
);
180 void uart_tx_flush(int idx
)
184 void uart_fill_lb(void *data
)
186 struct lb_serial serial
;
187 serial
.type
= LB_SERIAL_TYPE_MEMORY_MAPPED
;
188 serial
.baseaddr
= uart_platform_base(CONFIG_UART_FOR_CONSOLE
);
189 serial
.baud
= get_uart_baudrate();
191 serial
.input_hertz
= uart_platform_refclk();
192 serial
.uart_pci_addr
= CONFIG_UART_PCI_ADDR
;
193 lb_add_serial(&serial
, data
);
195 lb_add_console(LB_TAG_CONSOLE_SERIAL8250MEM
, data
);