blob: 460abd1d9f5e589342be198467df54c1f42aabd6 [file] [log] [blame]
Daniel Hellstromb3309902008-03-28 10:00:33 +01001/* GRLIB APBUART Serial controller driver
2 *
Francois Retiefa50adb72015-10-28 10:35:12 +02003 * (C) Copyright 2008, 2015
4 * Daniel Hellstrom, Cobham Gaisler, daniel@gaisler.com.
Daniel Hellstromb3309902008-03-28 10:00:33 +01005 *
Wolfgang Denk1a459662013-07-08 09:37:19 +02006 * SPDX-License-Identifier: GPL-2.0+
Daniel Hellstromb3309902008-03-28 10:00:33 +01007 */
8
9#include <common.h>
Francois Retiefa50adb72015-10-28 10:35:12 +020010#include <asm/io.h>
Marek Vasutaf7be3b2012-09-13 12:25:07 +020011#include <serial.h>
Francois Retiefa50adb72015-10-28 10:35:12 +020012#include <watchdog.h>
Daniel Hellstromb3309902008-03-28 10:00:33 +010013
14DECLARE_GLOBAL_DATA_PTR;
15
Francois Retiefa50adb72015-10-28 10:35:12 +020016static unsigned leon2_serial_calc_scaler(unsigned freq, unsigned baud)
17{
18 return (((freq*10) / (baud*8)) - 5) / 10;
19}
20
Marek Vasutaf7be3b2012-09-13 12:25:07 +020021static int leon2_serial_init(void)
Daniel Hellstromb3309902008-03-28 10:00:33 +010022{
Francois Retiefa50adb72015-10-28 10:35:12 +020023 LEON2_regs *leon2 = (LEON2_regs *)LEON2_PREGS;
Daniel Hellstromb3309902008-03-28 10:00:33 +010024 LEON2_Uart_regs *regs;
25 unsigned int tmp;
26
Daniel Hellstromb3309902008-03-28 10:00:33 +010027#if LEON2_CONSOLE_SELECT == LEON_CONSOLE_UART1
Francois Retiefa50adb72015-10-28 10:35:12 +020028 regs = (LEON2_Uart_regs *)&leon2->UART_Channel_1;
Daniel Hellstromb3309902008-03-28 10:00:33 +010029#else
Francois Retiefa50adb72015-10-28 10:35:12 +020030 regs = (LEON2_Uart_regs *)&leon2->UART_Channel_2;
Daniel Hellstromb3309902008-03-28 10:00:33 +010031#endif
32
Francois Retiefa50adb72015-10-28 10:35:12 +020033 /* Set scaler / baud rate */
34 tmp = leon2_serial_calc_scaler(CONFIG_SYS_CLK_FREQ, CONFIG_BAUDRATE);
35 writel(tmp, &regs->UART_Scaler);
Daniel Hellstromb3309902008-03-28 10:00:33 +010036
37 /* Let bit 11 be unchanged (debug bit for GRMON) */
Francois Retiefa50adb72015-10-28 10:35:12 +020038 tmp = readl(&regs->UART_Control) & LEON2_UART_CTRL_DBG;
39 tmp |= (LEON2_UART1_LOOPBACK_ENABLE << 7);
40 tmp |= (LEON2_UART1_FLOWCTRL_ENABLE << 6);
41 tmp |= (LEON2_UART1_PARITY_ENABLE << 5);
42 tmp |= (LEON2_UART1_ODDPAR_ENABLE << 4);
43 /* Receiver & transmitter enable */
44 tmp |= (LEON2_UART_CTRL_RE | LEON2_UART_CTRL_TE);
45 writel(tmp, &regs->UART_Control);
Daniel Hellstromb3309902008-03-28 10:00:33 +010046
Francois Retiefa50adb72015-10-28 10:35:12 +020047 gd->arch.uart = regs;
Daniel Hellstromb3309902008-03-28 10:00:33 +010048 return 0;
49}
50
Francois Retiefa50adb72015-10-28 10:35:12 +020051static inline LEON2_Uart_regs *leon2_get_uart_regs(void)
52{
53 LEON2_Uart_regs *uart = gd->arch.uart;
54
55 return uart;
56}
57
Marek Vasutaf7be3b2012-09-13 12:25:07 +020058static void leon2_serial_putc_raw(const char c)
Daniel Hellstromb3309902008-03-28 10:00:33 +010059{
Francois Retiefa50adb72015-10-28 10:35:12 +020060 LEON2_Uart_regs *uart = leon2_get_uart_regs();
Daniel Hellstromb3309902008-03-28 10:00:33 +010061
Francois Retiefa50adb72015-10-28 10:35:12 +020062 if (!uart)
63 return;
Daniel Hellstromb3309902008-03-28 10:00:33 +010064
65 /* Wait for last character to go. */
Francois Retiefa50adb72015-10-28 10:35:12 +020066 while (!(readl(&uart->UART_Status) & LEON2_UART_STAT_THE))
67 WATCHDOG_RESET();
Daniel Hellstromb3309902008-03-28 10:00:33 +010068
69 /* Send data */
Francois Retiefa50adb72015-10-28 10:35:12 +020070 writel(c, &uart->UART_Channel);
Daniel Hellstromb3309902008-03-28 10:00:33 +010071
72#ifdef LEON_DEBUG
73 /* Wait for data to be sent */
Francois Retiefa50adb72015-10-28 10:35:12 +020074 while (!(readl(&uart->UART_Status) & LEON2_UART_STAT_TSE))
75 WATCHDOG_RESET();
Daniel Hellstromb3309902008-03-28 10:00:33 +010076#endif
77}
78
Marek Vasutaf7be3b2012-09-13 12:25:07 +020079static void leon2_serial_putc(const char c)
80{
81 if (c == '\n')
82 leon2_serial_putc_raw('\r');
83
84 leon2_serial_putc_raw(c);
85}
86
Marek Vasutaf7be3b2012-09-13 12:25:07 +020087static int leon2_serial_getc(void)
Daniel Hellstromb3309902008-03-28 10:00:33 +010088{
Francois Retiefa50adb72015-10-28 10:35:12 +020089 LEON2_Uart_regs *uart = leon2_get_uart_regs();
Daniel Hellstromb3309902008-03-28 10:00:33 +010090
Francois Retiefa50adb72015-10-28 10:35:12 +020091 if (!uart)
92 return 0;
Daniel Hellstromb3309902008-03-28 10:00:33 +010093
94 /* Wait for a character to arrive. */
Francois Retiefa50adb72015-10-28 10:35:12 +020095 while (!(readl(&uart->UART_Status) & LEON2_UART_STAT_DR))
96 WATCHDOG_RESET();
Daniel Hellstromb3309902008-03-28 10:00:33 +010097
Francois Retiefa50adb72015-10-28 10:35:12 +020098 /* Read character data */
99 return readl(&uart->UART_Channel);
Daniel Hellstromb3309902008-03-28 10:00:33 +0100100}
101
Marek Vasutaf7be3b2012-09-13 12:25:07 +0200102static int leon2_serial_tstc(void)
Daniel Hellstromb3309902008-03-28 10:00:33 +0100103{
Francois Retiefa50adb72015-10-28 10:35:12 +0200104 LEON2_Uart_regs *uart = leon2_get_uart_regs();
Daniel Hellstromb3309902008-03-28 10:00:33 +0100105
Francois Retiefa50adb72015-10-28 10:35:12 +0200106 if (!uart)
107 return 0;
Daniel Hellstromb3309902008-03-28 10:00:33 +0100108
Francois Retiefa50adb72015-10-28 10:35:12 +0200109 return readl(&uart->UART_Status) & LEON2_UART_STAT_DR;
Daniel Hellstromb3309902008-03-28 10:00:33 +0100110}
111
Marek Vasutaf7be3b2012-09-13 12:25:07 +0200112static void leon2_serial_setbrg(void)
Daniel Hellstromb3309902008-03-28 10:00:33 +0100113{
Francois Retiefa50adb72015-10-28 10:35:12 +0200114 LEON2_Uart_regs *uart = leon2_get_uart_regs();
Daniel Hellstromb3309902008-03-28 10:00:33 +0100115 unsigned int scaler;
Daniel Hellstromb3309902008-03-28 10:00:33 +0100116
Francois Retiefa50adb72015-10-28 10:35:12 +0200117 if (!uart)
118 return;
Daniel Hellstromb3309902008-03-28 10:00:33 +0100119
Francois Retiefa50adb72015-10-28 10:35:12 +0200120 if (!gd->baudrate)
121 gd->baudrate = CONFIG_BAUDRATE;
122
Daniel Hellstromff0b9b72010-01-22 11:49:04 +0100123 scaler = leon2_serial_calc_scaler(CONFIG_SYS_CLK_FREQ, gd->baudrate);
Francois Retiefa50adb72015-10-28 10:35:12 +0200124
125 writel(scaler, &uart->UART_Scaler);
Daniel Hellstromb3309902008-03-28 10:00:33 +0100126}
Marek Vasutaf7be3b2012-09-13 12:25:07 +0200127
Marek Vasutaf7be3b2012-09-13 12:25:07 +0200128static struct serial_device leon2_serial_drv = {
129 .name = "leon2_serial",
130 .start = leon2_serial_init,
131 .stop = NULL,
132 .setbrg = leon2_serial_setbrg,
133 .putc = leon2_serial_putc,
Marek Vasutec3fd682012-10-06 14:07:02 +0000134 .puts = default_serial_puts,
Marek Vasutaf7be3b2012-09-13 12:25:07 +0200135 .getc = leon2_serial_getc,
136 .tstc = leon2_serial_tstc,
137};
138
139void leon2_serial_initialize(void)
140{
141 serial_register(&leon2_serial_drv);
142}
143
144__weak struct serial_device *default_serial_console(void)
145{
146 return &leon2_serial_drv;
147}