blob: c4a49ed369187b77ff70744eaa1c1614988a775d [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>
Marek Vasut29b5ff72012-09-13 12:25:48 +020012#include <serial.h>
Francois Retiefa50adb72015-10-28 10:35:12 +020013#include <watchdog.h>
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010014
15DECLARE_GLOBAL_DATA_PTR;
16
Daniel Hellstrom898cc812010-01-25 09:54:51 +010017/* Select which UART that will become u-boot console */
18#ifndef CONFIG_SYS_GRLIB_APBUART_INDEX
19#define CONFIG_SYS_GRLIB_APBUART_INDEX 0
20#endif
21
Marek Vasut29b5ff72012-09-13 12:25:48 +020022static int leon3_serial_init(void)
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010023{
Francois Retiefa50adb72015-10-28 10:35:12 +020024 ambapp_dev_apbuart *uart;
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010025 ambapp_apbdev apbdev;
26 unsigned int tmp;
27
28 /* find UART */
Daniel Hellstrom898cc812010-01-25 09:54:51 +010029 if (ambapp_apb_find(&ambapp_plb, VENDOR_GAISLER, GAISLER_APBUART,
30 CONFIG_SYS_GRLIB_APBUART_INDEX, &apbdev) != 1)
Francois Retiefa50adb72015-10-28 10:35:12 +020031 return -1; /* didn't find hardware */
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010032
Francois Retiefa50adb72015-10-28 10:35:12 +020033 /* found apbuart, let's init .. */
34 uart = (ambapp_dev_apbuart *) apbdev.address;
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010035
Francois Retiefa50adb72015-10-28 10:35:12 +020036 /* Set scaler / baud rate */
37 tmp = (((CONFIG_SYS_CLK_FREQ*10) / (CONFIG_BAUDRATE*8)) - 5)/10;
38 writel(tmp, &uart->scaler);
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010039
Francois Retiefa50adb72015-10-28 10:35:12 +020040 /* Let bit 11 be unchanged (debug bit for GRMON) */
41 tmp = readl(&uart->ctrl) & LEON_REG_UART_CTRL_DBG;
42 /* Receiver & transmitter enable */
43 tmp |= LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE;
44 writel(tmp, &uart->ctrl);
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010045
Francois Retiefa50adb72015-10-28 10:35:12 +020046 gd->arch.uart = uart;
47 return 0;
48}
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010049
Francois Retiefa50adb72015-10-28 10:35:12 +020050static inline ambapp_dev_apbuart *leon3_get_uart_regs(void)
51{
52 ambapp_dev_apbuart *uart = gd->arch.uart;
53 return uart;
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010054}
55
Marek Vasut29b5ff72012-09-13 12:25:48 +020056static void leon3_serial_putc_raw(const char c)
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010057{
Francois Retiefa50adb72015-10-28 10:35:12 +020058 ambapp_dev_apbuart * const uart = leon3_get_uart_regs();
59
60 if (!uart)
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010061 return;
62
63 /* Wait for last character to go. */
Francois Retiefa50adb72015-10-28 10:35:12 +020064 while (!(readl(&uart->status) & LEON_REG_UART_STATUS_THE))
65 WATCHDOG_RESET();
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010066
67 /* Send data */
Francois Retiefa50adb72015-10-28 10:35:12 +020068 writel(c, &uart->data);
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010069
70#ifdef LEON_DEBUG
71 /* Wait for data to be sent */
Francois Retiefa50adb72015-10-28 10:35:12 +020072 while (!(readl(&uart->status) & LEON_REG_UART_STATUS_TSE))
73 WATCHDOG_RESET();
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010074#endif
75}
76
Marek Vasut29b5ff72012-09-13 12:25:48 +020077static void leon3_serial_putc(const char c)
78{
79 if (c == '\n')
80 leon3_serial_putc_raw('\r');
81
82 leon3_serial_putc_raw(c);
83}
84
Marek Vasut29b5ff72012-09-13 12:25:48 +020085static int leon3_serial_getc(void)
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010086{
Francois Retiefa50adb72015-10-28 10:35:12 +020087 ambapp_dev_apbuart * const uart = leon3_get_uart_regs();
88
89 if (!uart)
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010090 return 0;
91
92 /* Wait for a character to arrive. */
Francois Retiefa50adb72015-10-28 10:35:12 +020093 while (!(readl(&uart->status) & LEON_REG_UART_STATUS_DR))
94 WATCHDOG_RESET();
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010095
Francois Retiefa50adb72015-10-28 10:35:12 +020096 /* Read character data */
97 return readl(&uart->data);
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010098}
99
Marek Vasut29b5ff72012-09-13 12:25:48 +0200100static int leon3_serial_tstc(void)
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100101{
Francois Retiefa50adb72015-10-28 10:35:12 +0200102 ambapp_dev_apbuart * const uart = leon3_get_uart_regs();
103
104 if (!uart)
105 return 0;
106
107 return readl(&uart->status) & LEON_REG_UART_STATUS_DR;
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100108}
109
110/* set baud rate for uart */
Marek Vasut29b5ff72012-09-13 12:25:48 +0200111static void leon3_serial_setbrg(void)
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100112{
Francois Retiefa50adb72015-10-28 10:35:12 +0200113 ambapp_dev_apbuart * const uart = leon3_get_uart_regs();
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100114 unsigned int scaler;
Francois Retiefa50adb72015-10-28 10:35:12 +0200115
116 if (!uart)
117 return;
118
119 if (!gd->baudrate)
120 gd->baudrate = CONFIG_BAUDRATE;
121
122 scaler = (((CONFIG_SYS_CLK_FREQ*10) / (gd->baudrate*8)) - 5)/10;
123
124 writel(scaler, &uart->scaler);
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100125}
Marek Vasut29b5ff72012-09-13 12:25:48 +0200126
Marek Vasut29b5ff72012-09-13 12:25:48 +0200127static struct serial_device leon3_serial_drv = {
128 .name = "leon3_serial",
129 .start = leon3_serial_init,
130 .stop = NULL,
131 .setbrg = leon3_serial_setbrg,
132 .putc = leon3_serial_putc,
Marek Vasutec3fd682012-10-06 14:07:02 +0000133 .puts = default_serial_puts,
Marek Vasut29b5ff72012-09-13 12:25:48 +0200134 .getc = leon3_serial_getc,
135 .tstc = leon3_serial_tstc,
136};
137
138void leon3_serial_initialize(void)
139{
140 serial_register(&leon3_serial_drv);
141}
142
143__weak struct serial_device *default_serial_console(void)
144{
145 return &leon3_serial_drv;
146}