blob: 5348a78303b6ab9d96348341b4a1818f749764ae [file] [log] [blame]
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +01001/* GRLIB APBUART Serial controller driver
2 *
Francois Retiefa50adb72015-10-28 10:35:12 +02003 * (C) Copyright 2007, 2015
4 * Daniel Hellstrom, Cobham Gaisler, daniel@gaisler.com.
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +01005 *
Wolfgang Denk1a459662013-07-08 09:37:19 +02006 * SPDX-License-Identifier: GPL-2.0+
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +01007 */
8
9#include <common.h>
Francois Retiefa50adb72015-10-28 10:35:12 +020010#include <asm/io.h>
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010011#include <ambapp.h>
Daniel Hellstromf2879f52010-01-21 16:09:37 +010012#include <grlib/apbuart.h>
Marek Vasut29b5ff72012-09-13 12:25:48 +020013#include <serial.h>
Francois Retiefa50adb72015-10-28 10:35:12 +020014#include <watchdog.h>
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010015
16DECLARE_GLOBAL_DATA_PTR;
17
Daniel Hellstrom898cc812010-01-25 09:54:51 +010018/* Select which UART that will become u-boot console */
19#ifndef CONFIG_SYS_GRLIB_APBUART_INDEX
20#define CONFIG_SYS_GRLIB_APBUART_INDEX 0
21#endif
22
Daniel Hellstromff0b9b72010-01-22 11:49:04 +010023static unsigned apbuart_calc_scaler(unsigned apbuart_freq, unsigned baud)
24{
25 return (((apbuart_freq * 10) / (baud * 8)) - 5) / 10;
26}
27
Marek Vasut29b5ff72012-09-13 12:25:48 +020028static int leon3_serial_init(void)
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010029{
Francois Retiefa50adb72015-10-28 10:35:12 +020030 ambapp_dev_apbuart *uart;
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010031 ambapp_apbdev apbdev;
32 unsigned int tmp;
33
34 /* find UART */
Daniel Hellstrom898cc812010-01-25 09:54:51 +010035 if (ambapp_apb_find(&ambapp_plb, VENDOR_GAISLER, GAISLER_APBUART,
Francois Retiefe43ce3f2015-10-29 12:55:34 +020036 CONFIG_SYS_GRLIB_APBUART_INDEX, &apbdev) != 1) {
Francois Retief58e55852015-11-23 09:49:57 +020037 gd->flags &= ~GD_FLG_SERIAL_READY;
Francois Retiefe43ce3f2015-10-29 12:55:34 +020038 panic("%s: apbuart not found!\n", __func__);
Francois Retiefa50adb72015-10-28 10:35:12 +020039 return -1; /* didn't find hardware */
Francois Retiefe43ce3f2015-10-29 12:55:34 +020040 }
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010041
Francois Retiefa50adb72015-10-28 10:35:12 +020042 /* found apbuart, let's init .. */
43 uart = (ambapp_dev_apbuart *) apbdev.address;
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010044
Daniel Hellstromff0b9b72010-01-22 11:49:04 +010045 /* APBUART Frequency is equal to bus frequency */
46 gd->arch.uart_freq = ambapp_bus_freq(&ambapp_plb, apbdev.ahb_bus_index);
47
Francois Retiefa50adb72015-10-28 10:35:12 +020048 /* Set scaler / baud rate */
Daniel Hellstromff0b9b72010-01-22 11:49:04 +010049 tmp = apbuart_calc_scaler(gd->arch.uart_freq, CONFIG_BAUDRATE);
Francois Retiefa50adb72015-10-28 10:35:12 +020050 writel(tmp, &uart->scaler);
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010051
Francois Retiefa50adb72015-10-28 10:35:12 +020052 /* Let bit 11 be unchanged (debug bit for GRMON) */
Daniel Hellstromf2879f52010-01-21 16:09:37 +010053 tmp = readl(&uart->ctrl) & APBUART_CTRL_DBG;
Francois Retiefa50adb72015-10-28 10:35:12 +020054 /* Receiver & transmitter enable */
Daniel Hellstromf2879f52010-01-21 16:09:37 +010055 tmp |= APBUART_CTRL_RE | APBUART_CTRL_TE;
Francois Retiefa50adb72015-10-28 10:35:12 +020056 writel(tmp, &uart->ctrl);
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010057
Francois Retiefa50adb72015-10-28 10:35:12 +020058 gd->arch.uart = uart;
59 return 0;
60}
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010061
Francois Retiefa50adb72015-10-28 10:35:12 +020062static inline ambapp_dev_apbuart *leon3_get_uart_regs(void)
63{
64 ambapp_dev_apbuart *uart = gd->arch.uart;
65 return uart;
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010066}
67
Marek Vasut29b5ff72012-09-13 12:25:48 +020068static void leon3_serial_putc_raw(const char c)
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010069{
Francois Retiefa50adb72015-10-28 10:35:12 +020070 ambapp_dev_apbuart * const uart = leon3_get_uart_regs();
71
72 if (!uart)
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010073 return;
74
75 /* Wait for last character to go. */
Daniel Hellstromf2879f52010-01-21 16:09:37 +010076 while (!(readl(&uart->status) & APBUART_STATUS_THE))
Francois Retiefa50adb72015-10-28 10:35:12 +020077 WATCHDOG_RESET();
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010078
79 /* Send data */
Francois Retiefa50adb72015-10-28 10:35:12 +020080 writel(c, &uart->data);
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010081
82#ifdef LEON_DEBUG
83 /* Wait for data to be sent */
Daniel Hellstromf2879f52010-01-21 16:09:37 +010084 while (!(readl(&uart->status) & APBUART_STATUS_TSE))
Francois Retiefa50adb72015-10-28 10:35:12 +020085 WATCHDOG_RESET();
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010086#endif
87}
88
Marek Vasut29b5ff72012-09-13 12:25:48 +020089static void leon3_serial_putc(const char c)
90{
91 if (c == '\n')
92 leon3_serial_putc_raw('\r');
93
94 leon3_serial_putc_raw(c);
95}
96
Marek Vasut29b5ff72012-09-13 12:25:48 +020097static int leon3_serial_getc(void)
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010098{
Francois Retiefa50adb72015-10-28 10:35:12 +020099 ambapp_dev_apbuart * const uart = leon3_get_uart_regs();
100
101 if (!uart)
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100102 return 0;
103
104 /* Wait for a character to arrive. */
Daniel Hellstromf2879f52010-01-21 16:09:37 +0100105 while (!(readl(&uart->status) & APBUART_STATUS_DR))
Francois Retiefa50adb72015-10-28 10:35:12 +0200106 WATCHDOG_RESET();
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100107
Francois Retiefa50adb72015-10-28 10:35:12 +0200108 /* Read character data */
109 return readl(&uart->data);
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100110}
111
Marek Vasut29b5ff72012-09-13 12:25:48 +0200112static int leon3_serial_tstc(void)
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100113{
Francois Retiefa50adb72015-10-28 10:35:12 +0200114 ambapp_dev_apbuart * const uart = leon3_get_uart_regs();
115
116 if (!uart)
117 return 0;
118
Daniel Hellstromf2879f52010-01-21 16:09:37 +0100119 return readl(&uart->status) & APBUART_STATUS_DR;
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100120}
121
122/* set baud rate for uart */
Marek Vasut29b5ff72012-09-13 12:25:48 +0200123static void leon3_serial_setbrg(void)
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100124{
Francois Retiefa50adb72015-10-28 10:35:12 +0200125 ambapp_dev_apbuart * const uart = leon3_get_uart_regs();
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100126 unsigned int scaler;
Francois Retiefa50adb72015-10-28 10:35:12 +0200127
128 if (!uart)
129 return;
130
131 if (!gd->baudrate)
132 gd->baudrate = CONFIG_BAUDRATE;
133
Daniel Hellstromff0b9b72010-01-22 11:49:04 +0100134 if (!gd->arch.uart_freq)
135 gd->arch.uart_freq = CONFIG_SYS_CLK_FREQ;
136
137 scaler = apbuart_calc_scaler(gd->arch.uart_freq, gd->baudrate);
Francois Retiefa50adb72015-10-28 10:35:12 +0200138
139 writel(scaler, &uart->scaler);
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100140}
Marek Vasut29b5ff72012-09-13 12:25:48 +0200141
Marek Vasut29b5ff72012-09-13 12:25:48 +0200142static struct serial_device leon3_serial_drv = {
143 .name = "leon3_serial",
144 .start = leon3_serial_init,
145 .stop = NULL,
146 .setbrg = leon3_serial_setbrg,
147 .putc = leon3_serial_putc,
Marek Vasutec3fd682012-10-06 14:07:02 +0000148 .puts = default_serial_puts,
Marek Vasut29b5ff72012-09-13 12:25:48 +0200149 .getc = leon3_serial_getc,
150 .tstc = leon3_serial_tstc,
151};
152
153void leon3_serial_initialize(void)
154{
155 serial_register(&leon3_serial_drv);
156}
157
158__weak struct serial_device *default_serial_console(void)
159{
160 return &leon3_serial_drv;
161}
Francois Retiefe43ce3f2015-10-29 12:55:34 +0200162
163#ifdef CONFIG_DEBUG_UART_APBUART
164
165#include <debug_uart.h>
166
167static inline void _debug_uart_init(void)
168{
169 ambapp_dev_apbuart *uart = (ambapp_dev_apbuart *)CONFIG_DEBUG_UART_BASE;
Daniel Hellstromff0b9b72010-01-22 11:49:04 +0100170 uart->scaler = apbuart_calc_scaler(CONFIG_DEBUG_UART_CLOCK, CONFIG_BAUDRATE);
Francois Retiefe43ce3f2015-10-29 12:55:34 +0200171 uart->ctrl = APBUART_CTRL_RE | APBUART_CTRL_TE;
172}
173
174static inline void _debug_uart_putc(int ch)
175{
176 ambapp_dev_apbuart *uart = (ambapp_dev_apbuart *)CONFIG_DEBUG_UART_BASE;
177 while (!(readl(&uart->status) & APBUART_STATUS_THE))
178 WATCHDOG_RESET();
179 writel(ch, &uart->data);
180}
181
182DEBUG_UART_FUNCS
183
184#endif