blob: 66b377302700f39a93755ecebd186ab93012cd3f [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
Marek Vasut29b5ff72012-09-13 12:25:48 +020023static int leon3_serial_init(void)
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010024{
Francois Retiefa50adb72015-10-28 10:35:12 +020025 ambapp_dev_apbuart *uart;
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010026 ambapp_apbdev apbdev;
27 unsigned int tmp;
28
29 /* find UART */
Daniel Hellstrom898cc812010-01-25 09:54:51 +010030 if (ambapp_apb_find(&ambapp_plb, VENDOR_GAISLER, GAISLER_APBUART,
Francois Retiefe43ce3f2015-10-29 12:55:34 +020031 CONFIG_SYS_GRLIB_APBUART_INDEX, &apbdev) != 1) {
32 panic("%s: apbuart not found!\n", __func__);
Francois Retiefa50adb72015-10-28 10:35:12 +020033 return -1; /* didn't find hardware */
Francois Retiefe43ce3f2015-10-29 12:55:34 +020034 }
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010035
Francois Retiefa50adb72015-10-28 10:35:12 +020036 /* found apbuart, let's init .. */
37 uart = (ambapp_dev_apbuart *) apbdev.address;
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010038
Francois Retiefa50adb72015-10-28 10:35:12 +020039 /* Set scaler / baud rate */
40 tmp = (((CONFIG_SYS_CLK_FREQ*10) / (CONFIG_BAUDRATE*8)) - 5)/10;
41 writel(tmp, &uart->scaler);
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010042
Francois Retiefa50adb72015-10-28 10:35:12 +020043 /* Let bit 11 be unchanged (debug bit for GRMON) */
Daniel Hellstromf2879f52010-01-21 16:09:37 +010044 tmp = readl(&uart->ctrl) & APBUART_CTRL_DBG;
Francois Retiefa50adb72015-10-28 10:35:12 +020045 /* Receiver & transmitter enable */
Daniel Hellstromf2879f52010-01-21 16:09:37 +010046 tmp |= APBUART_CTRL_RE | APBUART_CTRL_TE;
Francois Retiefa50adb72015-10-28 10:35:12 +020047 writel(tmp, &uart->ctrl);
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010048
Francois Retiefa50adb72015-10-28 10:35:12 +020049 gd->arch.uart = uart;
50 return 0;
51}
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010052
Francois Retiefa50adb72015-10-28 10:35:12 +020053static inline ambapp_dev_apbuart *leon3_get_uart_regs(void)
54{
55 ambapp_dev_apbuart *uart = gd->arch.uart;
56 return uart;
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010057}
58
Marek Vasut29b5ff72012-09-13 12:25:48 +020059static void leon3_serial_putc_raw(const char c)
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010060{
Francois Retiefa50adb72015-10-28 10:35:12 +020061 ambapp_dev_apbuart * const uart = leon3_get_uart_regs();
62
63 if (!uart)
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010064 return;
65
66 /* Wait for last character to go. */
Daniel Hellstromf2879f52010-01-21 16:09:37 +010067 while (!(readl(&uart->status) & APBUART_STATUS_THE))
Francois Retiefa50adb72015-10-28 10:35:12 +020068 WATCHDOG_RESET();
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010069
70 /* Send data */
Francois Retiefa50adb72015-10-28 10:35:12 +020071 writel(c, &uart->data);
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010072
73#ifdef LEON_DEBUG
74 /* Wait for data to be sent */
Daniel Hellstromf2879f52010-01-21 16:09:37 +010075 while (!(readl(&uart->status) & APBUART_STATUS_TSE))
Francois Retiefa50adb72015-10-28 10:35:12 +020076 WATCHDOG_RESET();
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010077#endif
78}
79
Marek Vasut29b5ff72012-09-13 12:25:48 +020080static void leon3_serial_putc(const char c)
81{
82 if (c == '\n')
83 leon3_serial_putc_raw('\r');
84
85 leon3_serial_putc_raw(c);
86}
87
Marek Vasut29b5ff72012-09-13 12:25:48 +020088static int leon3_serial_getc(void)
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010089{
Francois Retiefa50adb72015-10-28 10:35:12 +020090 ambapp_dev_apbuart * const uart = leon3_get_uart_regs();
91
92 if (!uart)
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010093 return 0;
94
95 /* Wait for a character to arrive. */
Daniel Hellstromf2879f52010-01-21 16:09:37 +010096 while (!(readl(&uart->status) & APBUART_STATUS_DR))
Francois Retiefa50adb72015-10-28 10:35:12 +020097 WATCHDOG_RESET();
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010098
Francois Retiefa50adb72015-10-28 10:35:12 +020099 /* Read character data */
100 return readl(&uart->data);
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100101}
102
Marek Vasut29b5ff72012-09-13 12:25:48 +0200103static int leon3_serial_tstc(void)
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100104{
Francois Retiefa50adb72015-10-28 10:35:12 +0200105 ambapp_dev_apbuart * const uart = leon3_get_uart_regs();
106
107 if (!uart)
108 return 0;
109
Daniel Hellstromf2879f52010-01-21 16:09:37 +0100110 return readl(&uart->status) & APBUART_STATUS_DR;
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100111}
112
113/* set baud rate for uart */
Marek Vasut29b5ff72012-09-13 12:25:48 +0200114static void leon3_serial_setbrg(void)
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100115{
Francois Retiefa50adb72015-10-28 10:35:12 +0200116 ambapp_dev_apbuart * const uart = leon3_get_uart_regs();
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100117 unsigned int scaler;
Francois Retiefa50adb72015-10-28 10:35:12 +0200118
119 if (!uart)
120 return;
121
122 if (!gd->baudrate)
123 gd->baudrate = CONFIG_BAUDRATE;
124
125 scaler = (((CONFIG_SYS_CLK_FREQ*10) / (gd->baudrate*8)) - 5)/10;
126
127 writel(scaler, &uart->scaler);
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100128}
Marek Vasut29b5ff72012-09-13 12:25:48 +0200129
Marek Vasut29b5ff72012-09-13 12:25:48 +0200130static struct serial_device leon3_serial_drv = {
131 .name = "leon3_serial",
132 .start = leon3_serial_init,
133 .stop = NULL,
134 .setbrg = leon3_serial_setbrg,
135 .putc = leon3_serial_putc,
Marek Vasutec3fd682012-10-06 14:07:02 +0000136 .puts = default_serial_puts,
Marek Vasut29b5ff72012-09-13 12:25:48 +0200137 .getc = leon3_serial_getc,
138 .tstc = leon3_serial_tstc,
139};
140
141void leon3_serial_initialize(void)
142{
143 serial_register(&leon3_serial_drv);
144}
145
146__weak struct serial_device *default_serial_console(void)
147{
148 return &leon3_serial_drv;
149}
Francois Retiefe43ce3f2015-10-29 12:55:34 +0200150
151#ifdef CONFIG_DEBUG_UART_APBUART
152
153#include <debug_uart.h>
154
155static inline void _debug_uart_init(void)
156{
157 ambapp_dev_apbuart *uart = (ambapp_dev_apbuart *)CONFIG_DEBUG_UART_BASE;
158 uart->scaler = (((CONFIG_DEBUG_UART_CLOCK*10) / (CONFIG_BAUDRATE*8)) - 5)/10;
159 uart->ctrl = APBUART_CTRL_RE | APBUART_CTRL_TE;
160}
161
162static inline void _debug_uart_putc(int ch)
163{
164 ambapp_dev_apbuart *uart = (ambapp_dev_apbuart *)CONFIG_DEBUG_UART_BASE;
165 while (!(readl(&uart->status) & APBUART_STATUS_THE))
166 WATCHDOG_RESET();
167 writel(ch, &uart->data);
168}
169
170DEBUG_UART_FUNCS
171
172#endif