]>
Commit | Line | Data |
---|---|---|
5b3b1688 DD |
1 | /* |
2 | * This file is subject to the terms and conditions of the GNU General Public | |
3 | * License. See the file "COPYING" in the main directory of this archive | |
4 | * for more details. | |
5 | * | |
6 | * Copyright (C) 2004-2007 Cavium Networks | |
7 | */ | |
8 | #include <linux/console.h> | |
9 | #include <linux/module.h> | |
10 | #include <linux/init.h> | |
11 | #include <linux/platform_device.h> | |
12 | #include <linux/serial.h> | |
13 | #include <linux/serial_8250.h> | |
14 | #include <linux/serial_reg.h> | |
15 | #include <linux/tty.h> | |
ca4d3e67 | 16 | #include <linux/irq.h> |
5b3b1688 DD |
17 | |
18 | #include <asm/time.h> | |
19 | ||
20 | #include <asm/octeon/octeon.h> | |
21 | ||
5b3b1688 | 22 | #define DEBUG_UART 1 |
5b3b1688 DD |
23 | |
24 | unsigned int octeon_serial_in(struct uart_port *up, int offset) | |
25 | { | |
26 | int rv = cvmx_read_csr((uint64_t)(up->membase + (offset << 3))); | |
27 | if (offset == UART_IIR && (rv & 0xf) == 7) { | |
28 | /* Busy interrupt, read the USR (39) and try again. */ | |
29 | cvmx_read_csr((uint64_t)(up->membase + (39 << 3))); | |
30 | rv = cvmx_read_csr((uint64_t)(up->membase + (offset << 3))); | |
31 | } | |
32 | return rv; | |
33 | } | |
34 | ||
35 | void octeon_serial_out(struct uart_port *up, int offset, int value) | |
36 | { | |
37 | /* | |
38 | * If bits 6 or 7 of the OCTEON UART's LCR are set, it quits | |
39 | * working. | |
40 | */ | |
41 | if (offset == UART_LCR) | |
42 | value &= 0x9f; | |
43 | cvmx_write_csr((uint64_t)(up->membase + (offset << 3)), (u8)value); | |
44 | } | |
45 | ||
46 | /* | |
47 | * Allocated in .bss, so it is all zeroed. | |
48 | */ | |
49 | #define OCTEON_MAX_UARTS 3 | |
50 | static struct plat_serial8250_port octeon_uart8250_data[OCTEON_MAX_UARTS + 1]; | |
51 | static struct platform_device octeon_uart8250_device = { | |
52 | .name = "serial8250", | |
53 | .id = PLAT8250_DEV_PLATFORM, | |
54 | .dev = { | |
55 | .platform_data = octeon_uart8250_data, | |
56 | }, | |
57 | }; | |
58 | ||
59 | static void __init octeon_uart_set_common(struct plat_serial8250_port *p) | |
60 | { | |
61 | p->flags = ASYNC_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE; | |
62 | p->type = PORT_OCTEON; | |
63 | p->iotype = UPIO_MEM; | |
64 | p->regshift = 3; /* I/O addresses are every 8 bytes */ | |
606c958e DD |
65 | if (octeon_is_simulation()) |
66 | /* Make simulator output fast*/ | |
67 | p->uartclk = 115200 * 16; | |
68 | else | |
4b8bca70 | 69 | p->uartclk = octeon_get_io_clock_rate(); |
5b3b1688 DD |
70 | p->serial_in = octeon_serial_in; |
71 | p->serial_out = octeon_serial_out; | |
72 | } | |
73 | ||
74 | static int __init octeon_serial_init(void) | |
75 | { | |
76 | int enable_uart0; | |
77 | int enable_uart1; | |
78 | int enable_uart2; | |
79 | struct plat_serial8250_port *p; | |
80 | ||
81 | #ifdef CONFIG_CAVIUM_OCTEON_2ND_KERNEL | |
82 | /* | |
83 | * If we are configured to run as the second of two kernels, | |
84 | * disable uart0 and enable uart1. Uart0 is owned by the first | |
85 | * kernel | |
86 | */ | |
87 | enable_uart0 = 0; | |
88 | enable_uart1 = 1; | |
89 | #else | |
90 | /* | |
91 | * We are configured for the first kernel. We'll enable uart0 | |
92 | * if the bootloader told us to use 0, otherwise will enable | |
93 | * uart 1. | |
94 | */ | |
95 | enable_uart0 = (octeon_get_boot_uart() == 0); | |
96 | enable_uart1 = (octeon_get_boot_uart() == 1); | |
97 | #ifdef CONFIG_KGDB | |
98 | enable_uart1 = 1; | |
99 | #endif | |
100 | #endif | |
101 | ||
102 | /* Right now CN52XX is the only chip with a third uart */ | |
103 | enable_uart2 = OCTEON_IS_MODEL(OCTEON_CN52XX); | |
104 | ||
105 | p = octeon_uart8250_data; | |
106 | if (enable_uart0) { | |
107 | /* Add a ttyS device for hardware uart 0 */ | |
108 | octeon_uart_set_common(p); | |
109 | p->membase = (void *) CVMX_MIO_UARTX_RBR(0); | |
110 | p->mapbase = CVMX_MIO_UARTX_RBR(0) & ((1ull << 49) - 1); | |
111 | p->irq = OCTEON_IRQ_UART0; | |
112 | p++; | |
113 | } | |
114 | ||
115 | if (enable_uart1) { | |
116 | /* Add a ttyS device for hardware uart 1 */ | |
117 | octeon_uart_set_common(p); | |
118 | p->membase = (void *) CVMX_MIO_UARTX_RBR(1); | |
119 | p->mapbase = CVMX_MIO_UARTX_RBR(1) & ((1ull << 49) - 1); | |
120 | p->irq = OCTEON_IRQ_UART1; | |
121 | p++; | |
122 | } | |
123 | if (enable_uart2) { | |
124 | /* Add a ttyS device for hardware uart 2 */ | |
125 | octeon_uart_set_common(p); | |
126 | p->membase = (void *) CVMX_MIO_UART2_RBR; | |
127 | p->mapbase = CVMX_MIO_UART2_RBR & ((1ull << 49) - 1); | |
128 | p->irq = OCTEON_IRQ_UART2; | |
129 | p++; | |
130 | } | |
131 | ||
132 | BUG_ON(p > &octeon_uart8250_data[OCTEON_MAX_UARTS]); | |
133 | ||
134 | return platform_device_register(&octeon_uart8250_device); | |
135 | } | |
136 | ||
137 | device_initcall(octeon_serial_init); |