]>
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 | |
20 | #define CONFIG_SYS_GRLIB_APBUART_INDEX 0 | |
21 | #endif | |
22 | ||
29b5ff7f | 23 | static int leon3_serial_init(void) |
1e9a164e | 24 | { |
a50adb7b | 25 | ambapp_dev_apbuart *uart; |
1e9a164e DH |
26 | ambapp_apbdev apbdev; |
27 | unsigned int tmp; | |
28 | ||
29 | /* find UART */ | |
898cc81d | 30 | if (ambapp_apb_find(&ambapp_plb, VENDOR_GAISLER, GAISLER_APBUART, |
e43ce3fc | 31 | CONFIG_SYS_GRLIB_APBUART_INDEX, &apbdev) != 1) { |
58e55856 | 32 | gd->flags &= ~GD_FLG_SERIAL_READY; |
e43ce3fc | 33 | panic("%s: apbuart not found!\n", __func__); |
a50adb7b | 34 | return -1; /* didn't find hardware */ |
e43ce3fc | 35 | } |
1e9a164e | 36 | |
a50adb7b FR |
37 | /* found apbuart, let's init .. */ |
38 | uart = (ambapp_dev_apbuart *) apbdev.address; | |
1e9a164e | 39 | |
a50adb7b FR |
40 | /* Set scaler / baud rate */ |
41 | tmp = (((CONFIG_SYS_CLK_FREQ*10) / (CONFIG_BAUDRATE*8)) - 5)/10; | |
42 | writel(tmp, &uart->scaler); | |
1e9a164e | 43 | |
a50adb7b | 44 | /* Let bit 11 be unchanged (debug bit for GRMON) */ |
f2879f59 | 45 | tmp = readl(&uart->ctrl) & APBUART_CTRL_DBG; |
a50adb7b | 46 | /* Receiver & transmitter enable */ |
f2879f59 | 47 | tmp |= APBUART_CTRL_RE | APBUART_CTRL_TE; |
a50adb7b | 48 | writel(tmp, &uart->ctrl); |
1e9a164e | 49 | |
a50adb7b FR |
50 | gd->arch.uart = uart; |
51 | return 0; | |
52 | } | |
1e9a164e | 53 | |
a50adb7b FR |
54 | static inline ambapp_dev_apbuart *leon3_get_uart_regs(void) |
55 | { | |
56 | ambapp_dev_apbuart *uart = gd->arch.uart; | |
57 | return uart; | |
1e9a164e DH |
58 | } |
59 | ||
29b5ff7f | 60 | static void leon3_serial_putc_raw(const char c) |
1e9a164e | 61 | { |
a50adb7b FR |
62 | ambapp_dev_apbuart * const uart = leon3_get_uart_regs(); |
63 | ||
64 | if (!uart) | |
1e9a164e DH |
65 | return; |
66 | ||
67 | /* Wait for last character to go. */ | |
f2879f59 | 68 | while (!(readl(&uart->status) & APBUART_STATUS_THE)) |
a50adb7b | 69 | WATCHDOG_RESET(); |
1e9a164e DH |
70 | |
71 | /* Send data */ | |
a50adb7b | 72 | writel(c, &uart->data); |
1e9a164e DH |
73 | |
74 | #ifdef LEON_DEBUG | |
75 | /* Wait for data to be sent */ | |
f2879f59 | 76 | while (!(readl(&uart->status) & APBUART_STATUS_TSE)) |
a50adb7b | 77 | WATCHDOG_RESET(); |
1e9a164e DH |
78 | #endif |
79 | } | |
80 | ||
29b5ff7f MV |
81 | static void leon3_serial_putc(const char c) |
82 | { | |
83 | if (c == '\n') | |
84 | leon3_serial_putc_raw('\r'); | |
85 | ||
86 | leon3_serial_putc_raw(c); | |
87 | } | |
88 | ||
29b5ff7f | 89 | static int leon3_serial_getc(void) |
1e9a164e | 90 | { |
a50adb7b FR |
91 | ambapp_dev_apbuart * const uart = leon3_get_uart_regs(); |
92 | ||
93 | if (!uart) | |
1e9a164e DH |
94 | return 0; |
95 | ||
96 | /* Wait for a character to arrive. */ | |
f2879f59 | 97 | while (!(readl(&uart->status) & APBUART_STATUS_DR)) |
a50adb7b | 98 | WATCHDOG_RESET(); |
1e9a164e | 99 | |
a50adb7b FR |
100 | /* Read character data */ |
101 | return readl(&uart->data); | |
1e9a164e DH |
102 | } |
103 | ||
29b5ff7f | 104 | static int leon3_serial_tstc(void) |
1e9a164e | 105 | { |
a50adb7b FR |
106 | ambapp_dev_apbuart * const uart = leon3_get_uart_regs(); |
107 | ||
108 | if (!uart) | |
109 | return 0; | |
110 | ||
f2879f59 | 111 | return readl(&uart->status) & APBUART_STATUS_DR; |
1e9a164e DH |
112 | } |
113 | ||
114 | /* set baud rate for uart */ | |
29b5ff7f | 115 | static void leon3_serial_setbrg(void) |
1e9a164e | 116 | { |
a50adb7b | 117 | ambapp_dev_apbuart * const uart = leon3_get_uart_regs(); |
1e9a164e | 118 | unsigned int scaler; |
a50adb7b FR |
119 | |
120 | if (!uart) | |
121 | return; | |
122 | ||
123 | if (!gd->baudrate) | |
124 | gd->baudrate = CONFIG_BAUDRATE; | |
125 | ||
126 | scaler = (((CONFIG_SYS_CLK_FREQ*10) / (gd->baudrate*8)) - 5)/10; | |
127 | ||
128 | writel(scaler, &uart->scaler); | |
1e9a164e | 129 | } |
29b5ff7f | 130 | |
29b5ff7f MV |
131 | static struct serial_device leon3_serial_drv = { |
132 | .name = "leon3_serial", | |
133 | .start = leon3_serial_init, | |
134 | .stop = NULL, | |
135 | .setbrg = leon3_serial_setbrg, | |
136 | .putc = leon3_serial_putc, | |
ec3fd689 | 137 | .puts = default_serial_puts, |
29b5ff7f MV |
138 | .getc = leon3_serial_getc, |
139 | .tstc = leon3_serial_tstc, | |
140 | }; | |
141 | ||
142 | void leon3_serial_initialize(void) | |
143 | { | |
144 | serial_register(&leon3_serial_drv); | |
145 | } | |
146 | ||
147 | __weak struct serial_device *default_serial_console(void) | |
148 | { | |
149 | return &leon3_serial_drv; | |
150 | } | |
e43ce3fc FR |
151 | |
152 | #ifdef CONFIG_DEBUG_UART_APBUART | |
153 | ||
154 | #include <debug_uart.h> | |
155 | ||
156 | static inline void _debug_uart_init(void) | |
157 | { | |
158 | ambapp_dev_apbuart *uart = (ambapp_dev_apbuart *)CONFIG_DEBUG_UART_BASE; | |
159 | uart->scaler = (((CONFIG_DEBUG_UART_CLOCK*10) / (CONFIG_BAUDRATE*8)) - 5)/10; | |
160 | uart->ctrl = APBUART_CTRL_RE | APBUART_CTRL_TE; | |
161 | } | |
162 | ||
163 | static inline void _debug_uart_putc(int ch) | |
164 | { | |
165 | ambapp_dev_apbuart *uart = (ambapp_dev_apbuart *)CONFIG_DEBUG_UART_BASE; | |
166 | while (!(readl(&uart->status) & APBUART_STATUS_THE)) | |
167 | WATCHDOG_RESET(); | |
168 | writel(ch, &uart->data); | |
169 | } | |
170 | ||
171 | DEBUG_UART_FUNCS | |
172 | ||
173 | #endif |