blob: 15d022673d64622fc505fdf0c04beb9ba428eb3e [file] [log] [blame]
Daniel Hellstromb552dbe2008-03-26 22:51:29 +01001/* GRLIB APBUART Serial controller driver
2 *
Francois Retiefff6929d2015-10-28 10:35:12 +02003 * (C) Copyright 2007, 2015
4 * Daniel Hellstrom, Cobham Gaisler, daniel@gaisler.com.
Daniel Hellstromb552dbe2008-03-26 22:51:29 +01005 *
Wolfgang Denkd79de1d2013-07-08 09:37:19 +02006 * SPDX-License-Identifier: GPL-2.0+
Daniel Hellstromb552dbe2008-03-26 22:51:29 +01007 */
8
9#include <common.h>
Francois Retiefff6929d2015-10-28 10:35:12 +020010#include <asm/io.h>
Daniel Hellstromb552dbe2008-03-26 22:51:29 +010011#include <ambapp.h>
Daniel Hellstrom9d59af92010-01-21 16:09:37 +010012#include <grlib/apbuart.h>
Marek Vasut2c91a962012-09-13 12:25:48 +020013#include <serial.h>
Francois Retiefff6929d2015-10-28 10:35:12 +020014#include <watchdog.h>
Daniel Hellstromb552dbe2008-03-26 22:51:29 +010015
16DECLARE_GLOBAL_DATA_PTR;
17
Daniel Hellstrom02e2a842010-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 Vasut2c91a962012-09-13 12:25:48 +020023static int leon3_serial_init(void)
Daniel Hellstromb552dbe2008-03-26 22:51:29 +010024{
Francois Retiefff6929d2015-10-28 10:35:12 +020025 ambapp_dev_apbuart *uart;
Daniel Hellstromb552dbe2008-03-26 22:51:29 +010026 ambapp_apbdev apbdev;
27 unsigned int tmp;
28
29 /* find UART */
Daniel Hellstrom02e2a842010-01-25 09:54:51 +010030 if (ambapp_apb_find(&ambapp_plb, VENDOR_GAISLER, GAISLER_APBUART,
Francois Retiefd18eb7b2015-10-29 12:55:34 +020031 CONFIG_SYS_GRLIB_APBUART_INDEX, &apbdev) != 1) {
Francois Retiefc35ce852015-11-23 09:49:57 +020032 gd->flags &= ~GD_FLG_SERIAL_READY;
Francois Retiefd18eb7b2015-10-29 12:55:34 +020033 panic("%s: apbuart not found!\n", __func__);
Francois Retiefff6929d2015-10-28 10:35:12 +020034 return -1; /* didn't find hardware */
Francois Retiefd18eb7b2015-10-29 12:55:34 +020035 }
Daniel Hellstromb552dbe2008-03-26 22:51:29 +010036
Francois Retiefff6929d2015-10-28 10:35:12 +020037 /* found apbuart, let's init .. */
38 uart = (ambapp_dev_apbuart *) apbdev.address;
Daniel Hellstromb552dbe2008-03-26 22:51:29 +010039
Francois Retiefff6929d2015-10-28 10:35:12 +020040 /* Set scaler / baud rate */
41 tmp = (((CONFIG_SYS_CLK_FREQ*10) / (CONFIG_BAUDRATE*8)) - 5)/10;
42 writel(tmp, &uart->scaler);
Daniel Hellstromb552dbe2008-03-26 22:51:29 +010043
Francois Retiefff6929d2015-10-28 10:35:12 +020044 /* Let bit 11 be unchanged (debug bit for GRMON) */
Daniel Hellstrom9d59af92010-01-21 16:09:37 +010045 tmp = readl(&uart->ctrl) & APBUART_CTRL_DBG;
Francois Retiefff6929d2015-10-28 10:35:12 +020046 /* Receiver & transmitter enable */
Daniel Hellstrom9d59af92010-01-21 16:09:37 +010047 tmp |= APBUART_CTRL_RE | APBUART_CTRL_TE;
Francois Retiefff6929d2015-10-28 10:35:12 +020048 writel(tmp, &uart->ctrl);
Daniel Hellstromb552dbe2008-03-26 22:51:29 +010049
Francois Retiefff6929d2015-10-28 10:35:12 +020050 gd->arch.uart = uart;
51 return 0;
52}
Daniel Hellstromb552dbe2008-03-26 22:51:29 +010053
Francois Retiefff6929d2015-10-28 10:35:12 +020054static inline ambapp_dev_apbuart *leon3_get_uart_regs(void)
55{
56 ambapp_dev_apbuart *uart = gd->arch.uart;
57 return uart;
Daniel Hellstromb552dbe2008-03-26 22:51:29 +010058}
59
Marek Vasut2c91a962012-09-13 12:25:48 +020060static void leon3_serial_putc_raw(const char c)
Daniel Hellstromb552dbe2008-03-26 22:51:29 +010061{
Francois Retiefff6929d2015-10-28 10:35:12 +020062 ambapp_dev_apbuart * const uart = leon3_get_uart_regs();
63
64 if (!uart)
Daniel Hellstromb552dbe2008-03-26 22:51:29 +010065 return;
66
67 /* Wait for last character to go. */
Daniel Hellstrom9d59af92010-01-21 16:09:37 +010068 while (!(readl(&uart->status) & APBUART_STATUS_THE))
Francois Retiefff6929d2015-10-28 10:35:12 +020069 WATCHDOG_RESET();
Daniel Hellstromb552dbe2008-03-26 22:51:29 +010070
71 /* Send data */
Francois Retiefff6929d2015-10-28 10:35:12 +020072 writel(c, &uart->data);
Daniel Hellstromb552dbe2008-03-26 22:51:29 +010073
74#ifdef LEON_DEBUG
75 /* Wait for data to be sent */
Daniel Hellstrom9d59af92010-01-21 16:09:37 +010076 while (!(readl(&uart->status) & APBUART_STATUS_TSE))
Francois Retiefff6929d2015-10-28 10:35:12 +020077 WATCHDOG_RESET();
Daniel Hellstromb552dbe2008-03-26 22:51:29 +010078#endif
79}
80
Marek Vasut2c91a962012-09-13 12:25:48 +020081static void leon3_serial_putc(const char c)
82{
83 if (c == '\n')
84 leon3_serial_putc_raw('\r');
85
86 leon3_serial_putc_raw(c);
87}
88
Marek Vasut2c91a962012-09-13 12:25:48 +020089static int leon3_serial_getc(void)
Daniel Hellstromb552dbe2008-03-26 22:51:29 +010090{
Francois Retiefff6929d2015-10-28 10:35:12 +020091 ambapp_dev_apbuart * const uart = leon3_get_uart_regs();
92
93 if (!uart)
Daniel Hellstromb552dbe2008-03-26 22:51:29 +010094 return 0;
95
96 /* Wait for a character to arrive. */
Daniel Hellstrom9d59af92010-01-21 16:09:37 +010097 while (!(readl(&uart->status) & APBUART_STATUS_DR))
Francois Retiefff6929d2015-10-28 10:35:12 +020098 WATCHDOG_RESET();
Daniel Hellstromb552dbe2008-03-26 22:51:29 +010099
Francois Retiefff6929d2015-10-28 10:35:12 +0200100 /* Read character data */
101 return readl(&uart->data);
Daniel Hellstromb552dbe2008-03-26 22:51:29 +0100102}
103
Marek Vasut2c91a962012-09-13 12:25:48 +0200104static int leon3_serial_tstc(void)
Daniel Hellstromb552dbe2008-03-26 22:51:29 +0100105{
Francois Retiefff6929d2015-10-28 10:35:12 +0200106 ambapp_dev_apbuart * const uart = leon3_get_uart_regs();
107
108 if (!uart)
109 return 0;
110
Daniel Hellstrom9d59af92010-01-21 16:09:37 +0100111 return readl(&uart->status) & APBUART_STATUS_DR;
Daniel Hellstromb552dbe2008-03-26 22:51:29 +0100112}
113
114/* set baud rate for uart */
Marek Vasut2c91a962012-09-13 12:25:48 +0200115static void leon3_serial_setbrg(void)
Daniel Hellstromb552dbe2008-03-26 22:51:29 +0100116{
Francois Retiefff6929d2015-10-28 10:35:12 +0200117 ambapp_dev_apbuart * const uart = leon3_get_uart_regs();
Daniel Hellstromb552dbe2008-03-26 22:51:29 +0100118 unsigned int scaler;
Francois Retiefff6929d2015-10-28 10:35:12 +0200119
120 if (!uart)
121 return;
122
123 if (!gd->baudrate)
124 gd->baudrate = CONFIG_BAUDRATE;
125
126 scaler = (((CONFIG_SYS_CLK_FREQ*10) / (gd->baudrate*8)) - 5)/10;
127
128 writel(scaler, &uart->scaler);
Daniel Hellstromb552dbe2008-03-26 22:51:29 +0100129}
Marek Vasut2c91a962012-09-13 12:25:48 +0200130
Marek Vasut2c91a962012-09-13 12:25:48 +0200131static struct serial_device leon3_serial_drv = {
132 .name = "leon3_serial",
133 .start = leon3_serial_init,
134 .stop = NULL,
135 .setbrg = leon3_serial_setbrg,
136 .putc = leon3_serial_putc,
Marek Vasutd9c64492012-10-06 14:07:02 +0000137 .puts = default_serial_puts,
Marek Vasut2c91a962012-09-13 12:25:48 +0200138 .getc = leon3_serial_getc,
139 .tstc = leon3_serial_tstc,
140};
141
142void leon3_serial_initialize(void)
143{
144 serial_register(&leon3_serial_drv);
145}
146
147__weak struct serial_device *default_serial_console(void)
148{
149 return &leon3_serial_drv;
150}
Francois Retiefd18eb7b2015-10-29 12:55:34 +0200151
152#ifdef CONFIG_DEBUG_UART_APBUART
153
154#include <debug_uart.h>
155
156static inline void _debug_uart_init(void)
157{
158 ambapp_dev_apbuart *uart = (ambapp_dev_apbuart *)CONFIG_DEBUG_UART_BASE;
159 uart->scaler = (((CONFIG_DEBUG_UART_CLOCK*10) / (CONFIG_BAUDRATE*8)) - 5)/10;
160 uart->ctrl = APBUART_CTRL_RE | APBUART_CTRL_TE;
161}
162
163static inline void _debug_uart_putc(int ch)
164{
165 ambapp_dev_apbuart *uart = (ambapp_dev_apbuart *)CONFIG_DEBUG_UART_BASE;
166 while (!(readl(&uart->status) & APBUART_STATUS_THE))
167 WATCHDOG_RESET();
168 writel(ch, &uart->data);
169}
170
171DEBUG_UART_FUNCS
172
173#endif