blob: 7999a19333a682837cf5b08e8f395107e24ec099 [file] [log] [blame]
Mike Frysinger9171fc82008-03-30 15:46:13 -04001/*
2 * serial.h - common serial defines for early debug and serial driver.
3 * any functions defined here must be always_inline since
4 * initcode cannot have function calls.
5 *
6 * Copyright (c) 2004-2007 Analog Devices Inc.
7 *
8 * Licensed under the GPL-2 or later.
9 */
10
11#ifndef __BFIN_CPU_SERIAL_H__
12#define __BFIN_CPU_SERIAL_H__
13
14#include <asm/blackfin.h>
15#include <asm/mach-common/bits/uart.h>
16
Mike Frysinger76339032008-10-11 21:52:17 -040017#ifndef CONFIG_UART_CONSOLE
18# define CONFIG_UART_CONSOLE 0
19#endif
20
Mike Frysinger9171fc82008-03-30 15:46:13 -040021#ifdef CONFIG_DEBUG_EARLY_SERIAL
22# define BFIN_DEBUG_EARLY_SERIAL 1
23#else
24# define BFIN_DEBUG_EARLY_SERIAL 0
25#endif
26
Mike Frysingerf9481582009-11-12 18:42:53 -050027#ifndef __ASSEMBLY__
28
Mike Frysingera409fdd2010-06-02 06:00:27 -040029#include <asm/portmux.h>
30
Mike Frysinger9171fc82008-03-30 15:46:13 -040031#define LOB(x) ((x) & 0xFF)
32#define HIB(x) (((x) >> 8) & 0xFF)
33
Mike Frysingercca07412010-12-17 15:25:09 -050034#if defined(__ADSPBF50x__) || defined(__ADSPBF54x__)
35# define BFIN_UART_HW_VER 2
36#else
37# define BFIN_UART_HW_VER 1
38#endif
39
Mike Frysingerf9481582009-11-12 18:42:53 -050040/*
41 * All Blackfin system MMRs are padded to 32bits even if the register
42 * itself is only 16bits. So use a helper macro to streamline this.
43 */
44#define __BFP(m) u16 m; u16 __pad_##m
45struct bfin_mmr_serial {
Mike Frysingercca07412010-12-17 15:25:09 -050046#if BFIN_UART_HW_VER == 2
Mike Frysingerf9481582009-11-12 18:42:53 -050047 __BFP(dll);
48 __BFP(dlh);
49 __BFP(gctl);
50 __BFP(lcr);
51 __BFP(mcr);
52 __BFP(lsr);
53 __BFP(msr);
54 __BFP(scr);
55 __BFP(ier_set);
56 __BFP(ier_clear);
57 __BFP(thr);
58 __BFP(rbr);
59#else
60 union {
61 u16 dll;
62 u16 thr;
63 const u16 rbr;
64 };
65 const u16 __spad0;
66 union {
67 u16 dlh;
68 u16 ier;
69 };
70 const u16 __spad1;
71 const __BFP(iir);
72 __BFP(lcr);
73 __BFP(mcr);
74 __BFP(lsr);
75 __BFP(msr);
76 __BFP(scr);
77 const u32 __spad2;
78 __BFP(gctl);
79#endif
80};
81#undef __BFP
82
Mike Frysingerbaaa4f92010-12-17 16:23:59 -050083#define __PASTE_UART(num, pfx, sfx) pfx##num##_##sfx
84#define _PASTE_UART(num, pfx, sfx) __PASTE_UART(num, pfx, sfx)
85#define MMR_UART(mmr) _PASTE_UART(CONFIG_UART_CONSOLE, UART, DLL)
86#define P_UART(pin) _PASTE_UART(CONFIG_UART_CONSOLE, P_UART, pin)
87
88#ifndef UART_DLL
89# define UART_DLL MMR_UART(DLL)
Mike Frysingerf9481582009-11-12 18:42:53 -050090#else
91# if CONFIG_UART_CONSOLE != 0
92# error CONFIG_UART_CONSOLE must be 0 on parts with only one UART
93# endif
Mike Frysinger9171fc82008-03-30 15:46:13 -040094#endif
Mike Frysingerbaaa4f92010-12-17 16:23:59 -050095#define pUART ((volatile struct bfin_mmr_serial *)UART_DLL)
Mike Frysinger9171fc82008-03-30 15:46:13 -040096
Mike Frysingercca07412010-12-17 15:25:09 -050097#if BFIN_UART_HW_VER == 2
Mike Frysinger9171fc82008-03-30 15:46:13 -040098# define ACCESS_LATCH()
99# define ACCESS_PORT_IER()
Mike Frysinger9171fc82008-03-30 15:46:13 -0400100#else
Mike Frysingerf9481582009-11-12 18:42:53 -0500101# define ACCESS_LATCH() \
102 bfin_write16(&pUART->lcr, bfin_read16(&pUART->lcr) | DLAB)
103# define ACCESS_PORT_IER() \
104 bfin_write16(&pUART->lcr, bfin_read16(&pUART->lcr) & ~DLAB)
Mike Frysinger9171fc82008-03-30 15:46:13 -0400105#endif
106
107__attribute__((always_inline))
108static inline void serial_do_portmux(void)
109{
Mike Frysingera409fdd2010-06-02 06:00:27 -0400110 if (!BFIN_DEBUG_EARLY_SERIAL) {
Mike Frysingerbaaa4f92010-12-17 16:23:59 -0500111 const unsigned short pins[] = { P_UART(RX), P_UART(TX), 0, };
Mike Frysingera409fdd2010-06-02 06:00:27 -0400112 peripheral_request_list(pins, "bfin-uart");
113 return;
114 }
115
Mike Frysingercca07412010-12-17 15:25:09 -0500116#if defined(__ADSPBF50x__)
117# define DO_MUX(port, mux_tx, mux_rx, tx, rx) \
118 bfin_write_PORT##port##_MUX((bfin_read_PORT##port##_MUX() & ~(PORT_x_MUX_##mux_tx##_MASK | PORT_x_MUX_##mux_rx##_MASK)) | PORT_x_MUX_##mux_tx##_FUNC_1 | PORT_x_MUX_##mux_rx##_FUNC_1); \
119 bfin_write_PORT##port##_FER(bfin_read_PORT##port##_FER() | P##port##tx | P##port##rx);
120 switch (CONFIG_UART_CONSOLE) {
121 case 0: DO_MUX(G, 7, 7, 12, 13); break; /* Port G; mux 7; PG12 and PG13 */
122 case 1: DO_MUX(F, 3, 3, 6, 7); break; /* Port F; mux 3; PF6 and PF7 */
123 }
124 SSYNC();
125#elif defined(__ADSPBF51x__)
Mike Frysinger51230e62008-10-11 21:15:53 -0400126# define DO_MUX(port, mux_tx, mux_rx, tx, rx) \
127 bfin_write_PORT##port##_MUX((bfin_read_PORT##port##_MUX() & ~(PORT_x_MUX_##mux_tx##_MASK | PORT_x_MUX_##mux_rx##_MASK)) | PORT_x_MUX_##mux_tx##_FUNC_2 | PORT_x_MUX_##mux_rx##_FUNC_2); \
128 bfin_write_PORT##port##_FER(bfin_read_PORT##port##_FER() | P##port##tx | P##port##rx);
129 switch (CONFIG_UART_CONSOLE) {
130 case 0: DO_MUX(G, 5, 5, 9, 10); break; /* Port G; mux 5; PG9 and PG10 */
131 case 1: DO_MUX(F, 2, 3, 14, 15); break; /* Port H; mux 2/3; PH14 and PH15 */
132 }
133 SSYNC();
134#elif defined(__ADSPBF52x__)
Mike Frysinger9171fc82008-03-30 15:46:13 -0400135# define DO_MUX(port, mux, tx, rx) \
136 bfin_write_PORT##port##_MUX((bfin_read_PORT##port##_MUX() & ~PORT_x_MUX_##mux##_MASK) | PORT_x_MUX_##mux##_FUNC_3); \
137 bfin_write_PORT##port##_FER(bfin_read_PORT##port##_FER() | P##port##tx | P##port##rx);
138 switch (CONFIG_UART_CONSOLE) {
139 case 0: DO_MUX(G, 2, 7, 8); break; /* Port G; mux 2; PG2 and PG8 */
140 case 1: DO_MUX(F, 5, 14, 15); break; /* Port F; mux 5; PF14 and PF15 */
141 }
142 SSYNC();
143#elif defined(__ADSPBF537__) || defined(__ADSPBF536__) || defined(__ADSPBF534__)
Mike Frysingerbaaa4f92010-12-17 16:23:59 -0500144 const uint16_t func[] = { PFDE, PFTE, };
145 bfin_write_PORT_MUX(bfin_read_PORT_MUX() & ~func[CONFIG_UART_CONSOLE]);
146 bfin_write_PORTF_FER(bfin_read_PORTF_FER() |
147 (1 << P_IDENT(P_UART(RX))) |
148 (1 << P_IDENT(P_UART(TX))));
Mike Frysinger9171fc82008-03-30 15:46:13 -0400149 SSYNC();
150#elif defined(__ADSPBF54x__)
151# define DO_MUX(port, tx, rx) \
152 bfin_write_PORT##port##_MUX((bfin_read_PORT##port##_MUX() & ~(PORT_x_MUX_##tx##_MASK | PORT_x_MUX_##rx##_MASK)) | PORT_x_MUX_##tx##_FUNC_1 | PORT_x_MUX_##rx##_FUNC_1); \
153 bfin_write_PORT##port##_FER(bfin_read_PORT##port##_FER() | P##port##tx | P##port##rx);
154 switch (CONFIG_UART_CONSOLE) {
155 case 0: DO_MUX(E, 7, 8); break; /* Port E; PE7 and PE8 */
156 case 1: DO_MUX(H, 0, 1); break; /* Port H; PH0 and PH1 */
157 case 2: DO_MUX(B, 4, 5); break; /* Port B; PB4 and PB5 */
158 case 3: DO_MUX(B, 6, 7); break; /* Port B; PB6 and PB7 */
159 }
160 SSYNC();
Mike Frysingerbaaa4f92010-12-17 16:23:59 -0500161#elif defined(__ADSPBF561__)
162 /* UART pins could be GPIO, but they aren't pin muxed. */
163#else
164# if (P_UART(RX) & P_DEFINED) || (P_UART(TX) & P_DEFINED)
165# error "missing portmux logic for UART"
166# endif
Mike Frysinger9171fc82008-03-30 15:46:13 -0400167#endif
168}
169
170__attribute__((always_inline))
171static inline void serial_early_init(void)
172{
173 /* handle portmux crap on different Blackfins */
174 serial_do_portmux();
175
Mike Frysingeraad4eca2009-04-04 09:10:27 -0400176 /* always enable UART -- avoids anomalies 05000309 and 05000350 */
Mike Frysingerf9481582009-11-12 18:42:53 -0500177 bfin_write16(&pUART->gctl, UCEN);
Mike Frysinger9171fc82008-03-30 15:46:13 -0400178
179 /* Set LCR to Word Lengh 8-bit word select */
Mike Frysingerf9481582009-11-12 18:42:53 -0500180 bfin_write16(&pUART->lcr, WLS_8);
Mike Frysinger9171fc82008-03-30 15:46:13 -0400181
182 SSYNC();
183}
184
185__attribute__((always_inline))
Mike Frysingerf790ef62008-12-10 12:33:54 -0500186static inline void serial_early_put_div(uint16_t divisor)
Mike Frysinger9171fc82008-03-30 15:46:13 -0400187{
Mike Frysinger9171fc82008-03-30 15:46:13 -0400188 /* Set DLAB in LCR to Access DLL and DLH */
189 ACCESS_LATCH();
190 SSYNC();
191
192 /* Program the divisor to get the baud rate we want */
Mike Frysingerf9481582009-11-12 18:42:53 -0500193 bfin_write16(&pUART->dll, LOB(divisor));
194 bfin_write16(&pUART->dlh, HIB(divisor));
Mike Frysinger9171fc82008-03-30 15:46:13 -0400195 SSYNC();
196
197 /* Clear DLAB in LCR to Access THR RBR IER */
198 ACCESS_PORT_IER();
199 SSYNC();
200}
201
Mike Frysingerf790ef62008-12-10 12:33:54 -0500202__attribute__((always_inline))
203static inline uint16_t serial_early_get_div(void)
204{
205 /* Set DLAB in LCR to Access DLL and DLH */
206 ACCESS_LATCH();
207 SSYNC();
208
Mike Frysingerf9481582009-11-12 18:42:53 -0500209 uint8_t dll = bfin_read16(&pUART->dll);
210 uint8_t dlh = bfin_read16(&pUART->dlh);
Mike Frysingerf790ef62008-12-10 12:33:54 -0500211 uint16_t divisor = (dlh << 8) | dll;
212
213 /* Clear DLAB in LCR to Access THR RBR IER */
214 ACCESS_PORT_IER();
215 SSYNC();
216
217 return divisor;
218}
219
Mike Frysingerf58bf802009-04-24 23:54:19 -0400220/* We cannot use get_sclk() early on as it uses caches in external memory */
221#if defined(BFIN_IN_INITCODE) || defined(CONFIG_DEBUG_EARLY_SERIAL)
222# define get_sclk() (CONFIG_CLKIN_HZ * CONFIG_VCO_MULT / CONFIG_SCLK_DIV)
223#endif
224
Mike Frysingerf790ef62008-12-10 12:33:54 -0500225__attribute__((always_inline))
226static inline void serial_early_set_baud(uint32_t baud)
227{
228 /* Translate from baud into divisor in terms of SCLK. The
229 * weird multiplication is to make sure we over sample just
230 * a little rather than under sample the incoming signals.
231 */
232 serial_early_put_div((get_sclk() + (baud * 8)) / (baud * 16) - ANOMALY_05000230);
233}
234
Mike Frysinger9171fc82008-03-30 15:46:13 -0400235#ifndef BFIN_IN_INITCODE
236__attribute__((always_inline))
237static inline void serial_early_puts(const char *s)
238{
239 if (BFIN_DEBUG_EARLY_SERIAL) {
240 serial_puts("Early: ");
241 serial_puts(s);
242 }
243}
244#endif
245
246#else
247
248.macro serial_early_init
249#ifdef CONFIG_DEBUG_EARLY_SERIAL
250 call _serial_initialize;
251#endif
252.endm
253
254.macro serial_early_set_baud
255#ifdef CONFIG_DEBUG_EARLY_SERIAL
256 R0.L = LO(CONFIG_BAUDRATE);
257 R0.H = HI(CONFIG_BAUDRATE);
258 call _serial_set_baud;
259#endif
260.endm
261
Mike Frysinger9171fc82008-03-30 15:46:13 -0400262/* Since we embed the string right into our .text section, we need
263 * to find its address. We do this by getting our PC and adding 2
264 * bytes (which is the length of the jump instruction). Then we
265 * pass this address to serial_puts().
266 */
267#ifdef CONFIG_DEBUG_EARLY_SERIAL
268# define serial_early_puts(str) \
269 call _get_pc; \
270 jump 1f; \
271 .ascii "Early:"; \
272 .ascii __FILE__; \
273 .ascii ": "; \
274 .ascii str; \
275 .asciz "\n"; \
276 .align 4; \
2771: \
278 R0 += 2; \
279 call _serial_puts;
280#else
281# define serial_early_puts(str)
282#endif
283
284#endif
285
286#endif