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