blob: bc6e7a172e5f010990eb0a00ea7b130bfc0f0b99 [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
Francois Retiefc2b37a02015-10-30 13:23:41 +020020/* Try to use CONFIG_CONS_INDEX, if available, it is numbered from 1 */
21#ifdef CONFIG_CONS_INDEX
22#define CONFIG_SYS_GRLIB_APBUART_INDEX (CONFIG_CONS_INDEX - 1)
23#else
Daniel Hellstrom898cc812010-01-25 09:54:51 +010024#define CONFIG_SYS_GRLIB_APBUART_INDEX 0
25#endif
Francois Retiefc2b37a02015-10-30 13:23:41 +020026#endif
Daniel Hellstrom898cc812010-01-25 09:54:51 +010027
Daniel Hellstromff0b9b72010-01-22 11:49:04 +010028static unsigned apbuart_calc_scaler(unsigned apbuart_freq, unsigned baud)
29{
30 return (((apbuart_freq * 10) / (baud * 8)) - 5) / 10;
31}
32
Marek Vasut29b5ff72012-09-13 12:25:48 +020033static int leon3_serial_init(void)
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010034{
Francois Retiefa50adb72015-10-28 10:35:12 +020035 ambapp_dev_apbuart *uart;
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010036 ambapp_apbdev apbdev;
37 unsigned int tmp;
38
39 /* find UART */
Daniel Hellstrom898cc812010-01-25 09:54:51 +010040 if (ambapp_apb_find(&ambapp_plb, VENDOR_GAISLER, GAISLER_APBUART,
Francois Retiefe43ce3f2015-10-29 12:55:34 +020041 CONFIG_SYS_GRLIB_APBUART_INDEX, &apbdev) != 1) {
Francois Retief58e55852015-11-23 09:49:57 +020042 gd->flags &= ~GD_FLG_SERIAL_READY;
Francois Retiefe43ce3f2015-10-29 12:55:34 +020043 panic("%s: apbuart not found!\n", __func__);
Francois Retiefa50adb72015-10-28 10:35:12 +020044 return -1; /* didn't find hardware */
Francois Retiefe43ce3f2015-10-29 12:55:34 +020045 }
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010046
Francois Retiefa50adb72015-10-28 10:35:12 +020047 /* found apbuart, let's init .. */
48 uart = (ambapp_dev_apbuart *) apbdev.address;
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010049
Daniel Hellstromff0b9b72010-01-22 11:49:04 +010050 /* APBUART Frequency is equal to bus frequency */
51 gd->arch.uart_freq = ambapp_bus_freq(&ambapp_plb, apbdev.ahb_bus_index);
52
Francois Retiefa50adb72015-10-28 10:35:12 +020053 /* Set scaler / baud rate */
Daniel Hellstromff0b9b72010-01-22 11:49:04 +010054 tmp = apbuart_calc_scaler(gd->arch.uart_freq, CONFIG_BAUDRATE);
Francois Retiefa50adb72015-10-28 10:35:12 +020055 writel(tmp, &uart->scaler);
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010056
Francois Retiefa50adb72015-10-28 10:35:12 +020057 /* Let bit 11 be unchanged (debug bit for GRMON) */
Daniel Hellstromf2879f52010-01-21 16:09:37 +010058 tmp = readl(&uart->ctrl) & APBUART_CTRL_DBG;
Francois Retiefa50adb72015-10-28 10:35:12 +020059 /* Receiver & transmitter enable */
Daniel Hellstromf2879f52010-01-21 16:09:37 +010060 tmp |= APBUART_CTRL_RE | APBUART_CTRL_TE;
Francois Retiefa50adb72015-10-28 10:35:12 +020061 writel(tmp, &uart->ctrl);
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010062
Francois Retiefa50adb72015-10-28 10:35:12 +020063 gd->arch.uart = uart;
64 return 0;
65}
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010066
Francois Retiefa50adb72015-10-28 10:35:12 +020067static inline ambapp_dev_apbuart *leon3_get_uart_regs(void)
68{
69 ambapp_dev_apbuart *uart = gd->arch.uart;
70 return uart;
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010071}
72
Marek Vasut29b5ff72012-09-13 12:25:48 +020073static void leon3_serial_putc_raw(const char c)
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010074{
Francois Retiefa50adb72015-10-28 10:35:12 +020075 ambapp_dev_apbuart * const uart = leon3_get_uart_regs();
76
77 if (!uart)
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010078 return;
79
80 /* Wait for last character to go. */
Daniel Hellstromf2879f52010-01-21 16:09:37 +010081 while (!(readl(&uart->status) & APBUART_STATUS_THE))
Francois Retiefa50adb72015-10-28 10:35:12 +020082 WATCHDOG_RESET();
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010083
84 /* Send data */
Francois Retiefa50adb72015-10-28 10:35:12 +020085 writel(c, &uart->data);
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010086
87#ifdef LEON_DEBUG
88 /* Wait for data to be sent */
Daniel Hellstromf2879f52010-01-21 16:09:37 +010089 while (!(readl(&uart->status) & APBUART_STATUS_TSE))
Francois Retiefa50adb72015-10-28 10:35:12 +020090 WATCHDOG_RESET();
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +010091#endif
92}
93
Marek Vasut29b5ff72012-09-13 12:25:48 +020094static void leon3_serial_putc(const char c)
95{
96 if (c == '\n')
97 leon3_serial_putc_raw('\r');
98
99 leon3_serial_putc_raw(c);
100}
101
Marek Vasut29b5ff72012-09-13 12:25:48 +0200102static int leon3_serial_getc(void)
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100103{
Francois Retiefa50adb72015-10-28 10:35:12 +0200104 ambapp_dev_apbuart * const uart = leon3_get_uart_regs();
105
106 if (!uart)
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100107 return 0;
108
109 /* Wait for a character to arrive. */
Daniel Hellstromf2879f52010-01-21 16:09:37 +0100110 while (!(readl(&uart->status) & APBUART_STATUS_DR))
Francois Retiefa50adb72015-10-28 10:35:12 +0200111 WATCHDOG_RESET();
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100112
Francois Retiefa50adb72015-10-28 10:35:12 +0200113 /* Read character data */
114 return readl(&uart->data);
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100115}
116
Marek Vasut29b5ff72012-09-13 12:25:48 +0200117static int leon3_serial_tstc(void)
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100118{
Francois Retiefa50adb72015-10-28 10:35:12 +0200119 ambapp_dev_apbuart * const uart = leon3_get_uart_regs();
120
121 if (!uart)
122 return 0;
123
Daniel Hellstromf2879f52010-01-21 16:09:37 +0100124 return readl(&uart->status) & APBUART_STATUS_DR;
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100125}
126
127/* set baud rate for uart */
Marek Vasut29b5ff72012-09-13 12:25:48 +0200128static void leon3_serial_setbrg(void)
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100129{
Francois Retiefa50adb72015-10-28 10:35:12 +0200130 ambapp_dev_apbuart * const uart = leon3_get_uart_regs();
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100131 unsigned int scaler;
Francois Retiefa50adb72015-10-28 10:35:12 +0200132
133 if (!uart)
134 return;
135
136 if (!gd->baudrate)
137 gd->baudrate = CONFIG_BAUDRATE;
138
Daniel Hellstromff0b9b72010-01-22 11:49:04 +0100139 if (!gd->arch.uart_freq)
140 gd->arch.uart_freq = CONFIG_SYS_CLK_FREQ;
141
142 scaler = apbuart_calc_scaler(gd->arch.uart_freq, gd->baudrate);
Francois Retiefa50adb72015-10-28 10:35:12 +0200143
144 writel(scaler, &uart->scaler);
Daniel Hellstrom1e9a1642008-03-26 22:51:29 +0100145}
Marek Vasut29b5ff72012-09-13 12:25:48 +0200146
Marek Vasut29b5ff72012-09-13 12:25:48 +0200147static struct serial_device leon3_serial_drv = {
148 .name = "leon3_serial",
149 .start = leon3_serial_init,
150 .stop = NULL,
151 .setbrg = leon3_serial_setbrg,
152 .putc = leon3_serial_putc,
Marek Vasutec3fd682012-10-06 14:07:02 +0000153 .puts = default_serial_puts,
Marek Vasut29b5ff72012-09-13 12:25:48 +0200154 .getc = leon3_serial_getc,
155 .tstc = leon3_serial_tstc,
156};
157
158void leon3_serial_initialize(void)
159{
160 serial_register(&leon3_serial_drv);
161}
162
163__weak struct serial_device *default_serial_console(void)
164{
165 return &leon3_serial_drv;
166}
Francois Retiefe43ce3f2015-10-29 12:55:34 +0200167
168#ifdef CONFIG_DEBUG_UART_APBUART
169
170#include <debug_uart.h>
171
172static inline void _debug_uart_init(void)
173{
174 ambapp_dev_apbuart *uart = (ambapp_dev_apbuart *)CONFIG_DEBUG_UART_BASE;
Daniel Hellstromff0b9b72010-01-22 11:49:04 +0100175 uart->scaler = apbuart_calc_scaler(CONFIG_DEBUG_UART_CLOCK, CONFIG_BAUDRATE);
Francois Retiefe43ce3f2015-10-29 12:55:34 +0200176 uart->ctrl = APBUART_CTRL_RE | APBUART_CTRL_TE;
177}
178
179static inline void _debug_uart_putc(int ch)
180{
181 ambapp_dev_apbuart *uart = (ambapp_dev_apbuart *)CONFIG_DEBUG_UART_BASE;
182 while (!(readl(&uart->status) & APBUART_STATUS_THE))
183 WATCHDOG_RESET();
184 writel(ch, &uart->data);
185}
186
187DEBUG_UART_FUNCS
188
189#endif