]>
Commit | Line | Data |
---|---|---|
1e9a164e DH |
1 | /* GRLIB APBUART Serial controller driver |
2 | * | |
3 | * (C) Copyright 2007 | |
4 | * Daniel Hellstrom, Gaisler Research, daniel@gaisler.com. | |
5 | * | |
1a459660 | 6 | * SPDX-License-Identifier: GPL-2.0+ |
1e9a164e DH |
7 | */ |
8 | ||
9 | #include <common.h> | |
10 | #include <asm/processor.h> | |
11 | #include <asm/leon.h> | |
12 | #include <ambapp.h> | |
29b5ff7f MV |
13 | #include <serial.h> |
14 | #include <linux/compiler.h> | |
1e9a164e DH |
15 | |
16 | DECLARE_GLOBAL_DATA_PTR; | |
17 | ||
1e9a164e DH |
18 | ambapp_dev_apbuart *leon3_apbuart = NULL; |
19 | ||
29b5ff7f | 20 | static int leon3_serial_init(void) |
1e9a164e DH |
21 | { |
22 | ambapp_apbdev apbdev; | |
23 | unsigned int tmp; | |
24 | ||
25 | /* find UART */ | |
26 | if (ambapp_apb_first(VENDOR_GAISLER, GAISLER_APBUART, &apbdev) == 1) { | |
27 | ||
28 | leon3_apbuart = (ambapp_dev_apbuart *) apbdev.address; | |
29 | ||
30 | /* found apbuart, let's init... | |
31 | * | |
32 | * Set scaler / baud rate | |
33 | * | |
34 | * Receiver & transmitter enable | |
35 | */ | |
6d0f6bcf | 36 | leon3_apbuart->scaler = CONFIG_SYS_GRLIB_APBUART_SCALER; |
1e9a164e DH |
37 | |
38 | /* Let bit 11 be unchanged (debug bit for GRMON) */ | |
39 | tmp = READ_WORD(leon3_apbuart->ctrl); | |
40 | ||
41 | leon3_apbuart->ctrl = ((tmp & LEON_REG_UART_CTRL_DBG) | | |
42 | LEON_REG_UART_CTRL_RE | | |
43 | LEON_REG_UART_CTRL_TE); | |
44 | ||
45 | return 0; | |
46 | } | |
47 | return -1; /* didn't find hardware */ | |
48 | } | |
49 | ||
29b5ff7f | 50 | static void leon3_serial_putc_raw(const char c) |
1e9a164e DH |
51 | { |
52 | if (!leon3_apbuart) | |
53 | return; | |
54 | ||
55 | /* Wait for last character to go. */ | |
56 | while (!(READ_WORD(leon3_apbuart->status) & LEON_REG_UART_STATUS_THE)) ; | |
57 | ||
58 | /* Send data */ | |
59 | leon3_apbuart->data = c; | |
60 | ||
61 | #ifdef LEON_DEBUG | |
62 | /* Wait for data to be sent */ | |
63 | while (!(READ_WORD(leon3_apbuart->status) & LEON_REG_UART_STATUS_TSE)) ; | |
64 | #endif | |
65 | } | |
66 | ||
29b5ff7f MV |
67 | static void leon3_serial_putc(const char c) |
68 | { | |
69 | if (c == '\n') | |
70 | leon3_serial_putc_raw('\r'); | |
71 | ||
72 | leon3_serial_putc_raw(c); | |
73 | } | |
74 | ||
29b5ff7f | 75 | static int leon3_serial_getc(void) |
1e9a164e DH |
76 | { |
77 | if (!leon3_apbuart) | |
78 | return 0; | |
79 | ||
80 | /* Wait for a character to arrive. */ | |
81 | while (!(READ_WORD(leon3_apbuart->status) & LEON_REG_UART_STATUS_DR)) ; | |
82 | ||
83 | /* read data */ | |
84 | return READ_WORD(leon3_apbuart->data); | |
85 | } | |
86 | ||
29b5ff7f | 87 | static int leon3_serial_tstc(void) |
1e9a164e DH |
88 | { |
89 | if (leon3_apbuart) | |
90 | return (READ_WORD(leon3_apbuart->status) & | |
91 | LEON_REG_UART_STATUS_DR); | |
92 | return 0; | |
93 | } | |
94 | ||
95 | /* set baud rate for uart */ | |
29b5ff7f | 96 | static void leon3_serial_setbrg(void) |
1e9a164e DH |
97 | { |
98 | /* update baud rate settings, read it from gd->baudrate */ | |
99 | unsigned int scaler; | |
100 | if (leon3_apbuart && (gd->baudrate > 0)) { | |
101 | scaler = | |
102 | (((CONFIG_SYS_CLK_FREQ * 10) / (gd->baudrate * 8)) - | |
103 | 5) / 10; | |
104 | leon3_apbuart->scaler = scaler; | |
105 | } | |
106 | return; | |
107 | } | |
29b5ff7f | 108 | |
29b5ff7f MV |
109 | static struct serial_device leon3_serial_drv = { |
110 | .name = "leon3_serial", | |
111 | .start = leon3_serial_init, | |
112 | .stop = NULL, | |
113 | .setbrg = leon3_serial_setbrg, | |
114 | .putc = leon3_serial_putc, | |
ec3fd689 | 115 | .puts = default_serial_puts, |
29b5ff7f MV |
116 | .getc = leon3_serial_getc, |
117 | .tstc = leon3_serial_tstc, | |
118 | }; | |
119 | ||
120 | void leon3_serial_initialize(void) | |
121 | { | |
122 | serial_register(&leon3_serial_drv); | |
123 | } | |
124 | ||
125 | __weak struct serial_device *default_serial_console(void) | |
126 | { | |
127 | return &leon3_serial_drv; | |
128 | } |