blob: f1dcab33778a85263cad0b8679b39de083260202 [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
Marek Vasut29b5ff72012-09-13 12:25:48 +020017static int leon3_serial_init(void)
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010018{
Francois Retiefa50adb72015-10-28 10:35:12 +020019 ambapp_dev_apbuart *uart;
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010020 ambapp_apbdev apbdev;
21 unsigned int tmp;
22
23 /* find UART */
Francois Retiefa50adb72015-10-28 10:35:12 +020024 if (ambapp_apb_first(VENDOR_GAISLER, GAISLER_APBUART, &apbdev) != 1)
25 return -1; /* didn't find hardware */
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010026
Francois Retiefa50adb72015-10-28 10:35:12 +020027 /* found apbuart, let's init .. */
28 uart = (ambapp_dev_apbuart *) apbdev.address;
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010029
Francois Retiefa50adb72015-10-28 10:35:12 +020030 /* Set scaler / baud rate */
31 tmp = (((CONFIG_SYS_CLK_FREQ*10) / (CONFIG_BAUDRATE*8)) - 5)/10;
32 writel(tmp, &uart->scaler);
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010033
Francois Retiefa50adb72015-10-28 10:35:12 +020034 /* Let bit 11 be unchanged (debug bit for GRMON) */
35 tmp = readl(&uart->ctrl) & LEON_REG_UART_CTRL_DBG;
36 /* Receiver & transmitter enable */
37 tmp |= LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE;
38 writel(tmp, &uart->ctrl);
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010039
Francois Retiefa50adb72015-10-28 10:35:12 +020040 gd->arch.uart = uart;
41 return 0;
42}
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010043
Francois Retiefa50adb72015-10-28 10:35:12 +020044static inline ambapp_dev_apbuart *leon3_get_uart_regs(void)
45{
46 ambapp_dev_apbuart *uart = gd->arch.uart;
47 return uart;
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010048}
49
Marek Vasut29b5ff72012-09-13 12:25:48 +020050static void leon3_serial_putc_raw(const char c)
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010051{
Francois Retiefa50adb72015-10-28 10:35:12 +020052 ambapp_dev_apbuart * const uart = leon3_get_uart_regs();
53
54 if (!uart)
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010055 return;
56
57 /* Wait for last character to go. */
Francois Retiefa50adb72015-10-28 10:35:12 +020058 while (!(readl(&uart->status) & LEON_REG_UART_STATUS_THE))
59 WATCHDOG_RESET();
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010060
61 /* Send data */
Francois Retiefa50adb72015-10-28 10:35:12 +020062 writel(c, &uart->data);
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010063
64#ifdef LEON_DEBUG
65 /* Wait for data to be sent */
Francois Retiefa50adb72015-10-28 10:35:12 +020066 while (!(readl(&uart->status) & LEON_REG_UART_STATUS_TSE))
67 WATCHDOG_RESET();
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010068#endif
69}
70
Marek Vasut29b5ff72012-09-13 12:25:48 +020071static void leon3_serial_putc(const char c)
72{
73 if (c == '\n')
74 leon3_serial_putc_raw('\r');
75
76 leon3_serial_putc_raw(c);
77}
78
Marek Vasut29b5ff72012-09-13 12:25:48 +020079static int leon3_serial_getc(void)
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010080{
Francois Retiefa50adb72015-10-28 10:35:12 +020081 ambapp_dev_apbuart * const uart = leon3_get_uart_regs();
82
83 if (!uart)
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010084 return 0;
85
86 /* Wait for a character to arrive. */
Francois Retiefa50adb72015-10-28 10:35:12 +020087 while (!(readl(&uart->status) & LEON_REG_UART_STATUS_DR))
88 WATCHDOG_RESET();
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010089
Francois Retiefa50adb72015-10-28 10:35:12 +020090 /* Read character data */
91 return readl(&uart->data);
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010092}
93
Marek Vasut29b5ff72012-09-13 12:25:48 +020094static int leon3_serial_tstc(void)
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010095{
Francois Retiefa50adb72015-10-28 10:35:12 +020096 ambapp_dev_apbuart * const uart = leon3_get_uart_regs();
97
98 if (!uart)
99 return 0;
100
101 return readl(&uart->status) & LEON_REG_UART_STATUS_DR;
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100102}
103
104/* set baud rate for uart */
Marek Vasut29b5ff72012-09-13 12:25:48 +0200105static void leon3_serial_setbrg(void)
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100106{
Francois Retiefa50adb72015-10-28 10:35:12 +0200107 ambapp_dev_apbuart * const uart = leon3_get_uart_regs();
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100108 unsigned int scaler;
Francois Retiefa50adb72015-10-28 10:35:12 +0200109
110 if (!uart)
111 return;
112
113 if (!gd->baudrate)
114 gd->baudrate = CONFIG_BAUDRATE;
115
116 scaler = (((CONFIG_SYS_CLK_FREQ*10) / (gd->baudrate*8)) - 5)/10;
117
118 writel(scaler, &uart->scaler);
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100119}
Marek Vasut29b5ff72012-09-13 12:25:48 +0200120
Marek Vasut29b5ff72012-09-13 12:25:48 +0200121static struct serial_device leon3_serial_drv = {
122 .name = "leon3_serial",
123 .start = leon3_serial_init,
124 .stop = NULL,
125 .setbrg = leon3_serial_setbrg,
126 .putc = leon3_serial_putc,
Marek Vasutec3fd682012-10-06 14:07:02 +0000127 .puts = default_serial_puts,
Marek Vasut29b5ff72012-09-13 12:25:48 +0200128 .getc = leon3_serial_getc,
129 .tstc = leon3_serial_tstc,
130};
131
132void leon3_serial_initialize(void)
133{
134 serial_register(&leon3_serial_drv);
135}
136
137__weak struct serial_device *default_serial_console(void)
138{
139 return &leon3_serial_drv;
140}