]>
Commit | Line | Data |
---|---|---|
1e9a164e DH |
1 | /* GRLIB APBUART Serial controller driver |
2 | * | |
a50adb7b FR |
3 | * (C) Copyright 2007, 2015 |
4 | * Daniel Hellstrom, Cobham Gaisler, daniel@gaisler.com. | |
1e9a164e | 5 | * |
1a459660 | 6 | * SPDX-License-Identifier: GPL-2.0+ |
1e9a164e DH |
7 | */ |
8 | ||
9 | #include <common.h> | |
a50adb7b | 10 | #include <asm/io.h> |
1e9a164e | 11 | #include <ambapp.h> |
f2879f59 | 12 | #include <grlib/apbuart.h> |
29b5ff7f | 13 | #include <serial.h> |
a50adb7b | 14 | #include <watchdog.h> |
1e9a164e DH |
15 | |
16 | DECLARE_GLOBAL_DATA_PTR; | |
17 | ||
898cc81d DH |
18 | /* Select which UART that will become u-boot console */ |
19 | #ifndef CONFIG_SYS_GRLIB_APBUART_INDEX | |
c2b37a0d FR |
20 | /* 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 | |
898cc81d DH |
24 | #define CONFIG_SYS_GRLIB_APBUART_INDEX 0 |
25 | #endif | |
c2b37a0d | 26 | #endif |
898cc81d | 27 | |
ff0b9b77 DH |
28 | static unsigned apbuart_calc_scaler(unsigned apbuart_freq, unsigned baud) |
29 | { | |
30 | return (((apbuart_freq * 10) / (baud * 8)) - 5) / 10; | |
31 | } | |
32 | ||
29b5ff7f | 33 | static int leon3_serial_init(void) |
1e9a164e | 34 | { |
a50adb7b | 35 | ambapp_dev_apbuart *uart; |
1e9a164e DH |
36 | ambapp_apbdev apbdev; |
37 | unsigned int tmp; | |
38 | ||
39 | /* find UART */ | |
898cc81d | 40 | if (ambapp_apb_find(&ambapp_plb, VENDOR_GAISLER, GAISLER_APBUART, |
e43ce3fc | 41 | CONFIG_SYS_GRLIB_APBUART_INDEX, &apbdev) != 1) { |
58e55856 | 42 | gd->flags &= ~GD_FLG_SERIAL_READY; |
e43ce3fc | 43 | panic("%s: apbuart not found!\n", __func__); |
a50adb7b | 44 | return -1; /* didn't find hardware */ |
e43ce3fc | 45 | } |
1e9a164e | 46 | |
a50adb7b FR |
47 | /* found apbuart, let's init .. */ |
48 | uart = (ambapp_dev_apbuart *) apbdev.address; | |
1e9a164e | 49 | |
ff0b9b77 DH |
50 | /* APBUART Frequency is equal to bus frequency */ |
51 | gd->arch.uart_freq = ambapp_bus_freq(&ambapp_plb, apbdev.ahb_bus_index); | |
52 | ||
a50adb7b | 53 | /* Set scaler / baud rate */ |
ff0b9b77 | 54 | tmp = apbuart_calc_scaler(gd->arch.uart_freq, CONFIG_BAUDRATE); |
a50adb7b | 55 | writel(tmp, &uart->scaler); |
1e9a164e | 56 | |
a50adb7b | 57 | /* Let bit 11 be unchanged (debug bit for GRMON) */ |
f2879f59 | 58 | tmp = readl(&uart->ctrl) & APBUART_CTRL_DBG; |
a50adb7b | 59 | /* Receiver & transmitter enable */ |
f2879f59 | 60 | tmp |= APBUART_CTRL_RE | APBUART_CTRL_TE; |
a50adb7b | 61 | writel(tmp, &uart->ctrl); |
1e9a164e | 62 | |
a50adb7b FR |
63 | gd->arch.uart = uart; |
64 | return 0; | |
65 | } | |
1e9a164e | 66 | |
a50adb7b FR |
67 | static inline ambapp_dev_apbuart *leon3_get_uart_regs(void) |
68 | { | |
69 | ambapp_dev_apbuart *uart = gd->arch.uart; | |
70 | return uart; | |
1e9a164e DH |
71 | } |
72 | ||
29b5ff7f | 73 | static void leon3_serial_putc_raw(const char c) |
1e9a164e | 74 | { |
a50adb7b FR |
75 | ambapp_dev_apbuart * const uart = leon3_get_uart_regs(); |
76 | ||
77 | if (!uart) | |
1e9a164e DH |
78 | return; |
79 | ||
80 | /* Wait for last character to go. */ | |
f2879f59 | 81 | while (!(readl(&uart->status) & APBUART_STATUS_THE)) |
a50adb7b | 82 | WATCHDOG_RESET(); |
1e9a164e DH |
83 | |
84 | /* Send data */ | |
a50adb7b | 85 | writel(c, &uart->data); |
1e9a164e DH |
86 | |
87 | #ifdef LEON_DEBUG | |
88 | /* Wait for data to be sent */ | |
f2879f59 | 89 | while (!(readl(&uart->status) & APBUART_STATUS_TSE)) |
a50adb7b | 90 | WATCHDOG_RESET(); |
1e9a164e DH |
91 | #endif |
92 | } | |
93 | ||
29b5ff7f MV |
94 | static 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 | ||
29b5ff7f | 102 | static int leon3_serial_getc(void) |
1e9a164e | 103 | { |
a50adb7b FR |
104 | ambapp_dev_apbuart * const uart = leon3_get_uart_regs(); |
105 | ||
106 | if (!uart) | |
1e9a164e DH |
107 | return 0; |
108 | ||
109 | /* Wait for a character to arrive. */ | |
f2879f59 | 110 | while (!(readl(&uart->status) & APBUART_STATUS_DR)) |
a50adb7b | 111 | WATCHDOG_RESET(); |
1e9a164e | 112 | |
a50adb7b FR |
113 | /* Read character data */ |
114 | return readl(&uart->data); | |
1e9a164e DH |
115 | } |
116 | ||
29b5ff7f | 117 | static int leon3_serial_tstc(void) |
1e9a164e | 118 | { |
a50adb7b FR |
119 | ambapp_dev_apbuart * const uart = leon3_get_uart_regs(); |
120 | ||
121 | if (!uart) | |
122 | return 0; | |
123 | ||
f2879f59 | 124 | return readl(&uart->status) & APBUART_STATUS_DR; |
1e9a164e DH |
125 | } |
126 | ||
127 | /* set baud rate for uart */ | |
29b5ff7f | 128 | static void leon3_serial_setbrg(void) |
1e9a164e | 129 | { |
a50adb7b | 130 | ambapp_dev_apbuart * const uart = leon3_get_uart_regs(); |
1e9a164e | 131 | unsigned int scaler; |
a50adb7b FR |
132 | |
133 | if (!uart) | |
134 | return; | |
135 | ||
136 | if (!gd->baudrate) | |
137 | gd->baudrate = CONFIG_BAUDRATE; | |
138 | ||
ff0b9b77 DH |
139 | 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); | |
a50adb7b FR |
143 | |
144 | writel(scaler, &uart->scaler); | |
1e9a164e | 145 | } |
29b5ff7f | 146 | |
29b5ff7f MV |
147 | static 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, | |
ec3fd689 | 153 | .puts = default_serial_puts, |
29b5ff7f MV |
154 | .getc = leon3_serial_getc, |
155 | .tstc = leon3_serial_tstc, | |
156 | }; | |
157 | ||
158 | void 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 | } | |
e43ce3fc FR |
167 | |
168 | #ifdef CONFIG_DEBUG_UART_APBUART | |
169 | ||
170 | #include <debug_uart.h> | |
171 | ||
172 | static inline void _debug_uart_init(void) | |
173 | { | |
174 | ambapp_dev_apbuart *uart = (ambapp_dev_apbuart *)CONFIG_DEBUG_UART_BASE; | |
ff0b9b77 | 175 | uart->scaler = apbuart_calc_scaler(CONFIG_DEBUG_UART_CLOCK, CONFIG_BAUDRATE); |
e43ce3fc FR |
176 | uart->ctrl = APBUART_CTRL_RE | APBUART_CTRL_TE; |
177 | } | |
178 | ||
179 | static 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 | ||
187 | DEBUG_UART_FUNCS | |
188 | ||
189 | #endif |