Sonic Zhang | 7a91b9b | 2012-08-16 11:16:02 +0800 | [diff] [blame] | 1 | /* |
| 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-2011 Analog Devices Inc. |
| 7 | * |
| 8 | * Licensed under the GPL-2 or later. |
| 9 | */ |
| 10 | |
| 11 | #ifndef __BFIN_CPU_SERIAL1_H__ |
| 12 | #define __BFIN_CPU_SERIAL1_H__ |
| 13 | |
| 14 | #include <asm/mach-common/bits/uart.h> |
| 15 | |
| 16 | #ifndef __ASSEMBLY__ |
| 17 | |
Sonic Zhang | c15c403 | 2013-02-05 19:10:34 +0800 | [diff] [blame] | 18 | #include <asm/clock.h> |
| 19 | |
Sonic Zhang | 7a91b9b | 2012-08-16 11:16:02 +0800 | [diff] [blame] | 20 | #define MMR_UART(n) _PASTE_UART(n, UART, DLL) |
| 21 | #ifdef UART_DLL |
| 22 | # define UART0_DLL UART_DLL |
| 23 | # if CONFIG_UART_CONSOLE != 0 |
| 24 | # error CONFIG_UART_CONSOLE must be 0 on parts with only one UART |
| 25 | # endif |
| 26 | #endif |
| 27 | #define UART_BASE MMR_UART(CONFIG_UART_CONSOLE) |
| 28 | |
| 29 | #define LOB(x) ((x) & 0xFF) |
| 30 | #define HIB(x) (((x) >> 8) & 0xFF) |
| 31 | |
| 32 | /* |
| 33 | * All Blackfin system MMRs are padded to 32bits even if the register |
| 34 | * itself is only 16bits. So use a helper macro to streamline this. |
| 35 | */ |
| 36 | struct bfin_mmr_serial { |
| 37 | #if BFIN_UART_HW_VER == 2 |
| 38 | u16 dll; |
| 39 | u16 __pad_0; |
| 40 | u16 dlh; |
| 41 | u16 __pad_1; |
| 42 | u16 gctl; |
| 43 | u16 __pad_2; |
| 44 | u16 lcr; |
| 45 | u16 __pad_3; |
| 46 | u16 mcr; |
| 47 | u16 __pad_4; |
| 48 | u16 lsr; |
| 49 | u16 __pad_5; |
| 50 | u16 msr; |
| 51 | u16 __pad_6; |
| 52 | u16 scr; |
| 53 | u16 __pad_7; |
| 54 | u16 ier_set; |
| 55 | u16 __pad_8; |
| 56 | u16 ier_clear; |
| 57 | u16 __pad_9; |
| 58 | u16 thr; |
| 59 | u16 __pad_10; |
| 60 | u16 rbr; |
| 61 | u16 __pad_11; |
| 62 | #else |
| 63 | union { |
| 64 | u16 dll; |
| 65 | u16 thr; |
| 66 | const u16 rbr; |
| 67 | }; |
| 68 | const u16 __spad0; |
| 69 | union { |
| 70 | u16 dlh; |
| 71 | u16 ier; |
| 72 | }; |
| 73 | const u16 __spad1; |
| 74 | const u16 iir; |
| 75 | u16 __pad_0; |
| 76 | u16 lcr; |
| 77 | u16 __pad_1; |
| 78 | u16 mcr; |
| 79 | u16 __pad_2; |
| 80 | u16 lsr; |
| 81 | u16 __pad_3; |
| 82 | u16 msr; |
| 83 | u16 __pad_4; |
| 84 | u16 scr; |
| 85 | u16 __pad_5; |
| 86 | const u32 __spad2; |
| 87 | u16 gctl; |
| 88 | u16 __pad_6; |
| 89 | #endif |
| 90 | }; |
| 91 | |
| 92 | #define uart_lsr_t uint32_t |
| 93 | #define _lsr_read(p) bfin_read(&p->lsr) |
| 94 | #define _lsr_write(p, v) bfin_write(&p->lsr, v) |
| 95 | |
| 96 | #if BFIN_UART_HW_VER == 2 |
| 97 | # define ACCESS_LATCH() |
| 98 | # define ACCESS_PORT_IER() |
| 99 | #else |
| 100 | # define ACCESS_LATCH() bfin_write_or(&pUART->lcr, DLAB) |
| 101 | # define ACCESS_PORT_IER() bfin_write_and(&pUART->lcr, ~DLAB) |
| 102 | #endif |
| 103 | |
| 104 | __attribute__((always_inline)) |
| 105 | static inline void serial_early_do_mach_portmux(char port, int mux_mask, |
| 106 | int mux_func, int port_pin) |
| 107 | { |
| 108 | switch (port) { |
| 109 | #if defined(__ADSPBF54x__) |
| 110 | case 'B': |
| 111 | bfin_write_PORTB_MUX((bfin_read_PORTB_MUX() & |
| 112 | ~mux_mask) | mux_func); |
| 113 | bfin_write_PORTB_FER(bfin_read_PORTB_FER() | port_pin); |
| 114 | break; |
| 115 | case 'E': |
| 116 | bfin_write_PORTE_MUX((bfin_read_PORTE_MUX() & |
| 117 | ~mux_mask) | mux_func); |
| 118 | bfin_write_PORTE_FER(bfin_read_PORTE_FER() | port_pin); |
| 119 | break; |
| 120 | #endif |
| 121 | #if defined(__ADSPBF50x__) || defined(__ADSPBF51x__) || defined(__ADSPBF52x__) |
| 122 | case 'F': |
| 123 | bfin_write_PORTF_MUX((bfin_read_PORTF_MUX() & |
| 124 | ~mux_mask) | mux_func); |
| 125 | bfin_write_PORTF_FER(bfin_read_PORTF_FER() | port_pin); |
| 126 | break; |
| 127 | case 'G': |
| 128 | bfin_write_PORTG_MUX((bfin_read_PORTG_MUX() & |
| 129 | ~mux_mask) | mux_func); |
| 130 | bfin_write_PORTG_FER(bfin_read_PORTG_FER() | port_pin); |
| 131 | break; |
| 132 | case 'H': |
| 133 | bfin_write_PORTH_MUX((bfin_read_PORTH_MUX() & |
| 134 | ~mux_mask) | mux_func); |
| 135 | bfin_write_PORTH_FER(bfin_read_PORTH_FER() | port_pin); |
| 136 | break; |
| 137 | #endif |
| 138 | default: |
| 139 | break; |
| 140 | } |
| 141 | } |
| 142 | |
| 143 | __attribute__((always_inline)) |
| 144 | static inline void serial_early_do_portmux(void) |
| 145 | { |
| 146 | #if defined(__ADSPBF50x__) |
| 147 | switch (CONFIG_UART_CONSOLE) { |
| 148 | case 0: |
| 149 | serial_early_do_mach_portmux('G', PORT_x_MUX_7_MASK, |
| 150 | PORT_x_MUX_7_FUNC_1, PG12); /* TX: G; mux 7; func 1; PG12 */ |
| 151 | serial_early_do_mach_portmux('G', PORT_x_MUX_7_MASK, |
| 152 | PORT_x_MUX_7_FUNC_1, PG13); /* RX: G; mux 7; func 1; PG13 */ |
| 153 | break; |
| 154 | case 1: |
| 155 | serial_early_do_mach_portmux('F', PORT_x_MUX_3_MASK, |
| 156 | PORT_x_MUX_3_FUNC_1, PF7); /* TX: F; mux 3; func 1; PF6 */ |
| 157 | serial_early_do_mach_portmux('F', PORT_x_MUX_3_MASK, |
| 158 | PORT_x_MUX_3_FUNC_1, PF6); /* RX: F; mux 3; func 1; PF7 */ |
| 159 | break; |
| 160 | } |
| 161 | #elif defined(__ADSPBF51x__) |
| 162 | switch (CONFIG_UART_CONSOLE) { |
| 163 | case 0: |
| 164 | serial_early_do_mach_portmux('G', PORT_x_MUX_5_MASK, |
| 165 | PORT_x_MUX_5_FUNC_2, PG9); /* TX: G; mux 5; func 2; PG9 */ |
| 166 | serial_early_do_mach_portmux('G', PORT_x_MUX_5_MASK, |
| 167 | PORT_x_MUX_5_FUNC_2, PG10); /* RX: G; mux 5; func 2; PG10 */ |
| 168 | break; |
| 169 | case 1: |
| 170 | serial_early_do_mach_portmux('H', PORT_x_MUX_3_MASK, |
| 171 | PORT_x_MUX_3_FUNC_2, PH7); /* TX: H; mux 3; func 2; PH6 */ |
| 172 | serial_early_do_mach_portmux('H', PORT_x_MUX_3_MASK, |
| 173 | PORT_x_MUX_3_FUNC_2, PH6); /* RX: H; mux 3; func 2; PH7 */ |
| 174 | break; |
| 175 | } |
| 176 | #elif defined(__ADSPBF52x__) |
| 177 | switch (CONFIG_UART_CONSOLE) { |
| 178 | case 0: |
| 179 | serial_early_do_mach_portmux('G', PORT_x_MUX_2_MASK, |
| 180 | PORT_x_MUX_2_FUNC_3, PG7); /* TX: G; mux 2; func 3; PG7 */ |
| 181 | serial_early_do_mach_portmux('G', PORT_x_MUX_2_MASK, |
| 182 | PORT_x_MUX_2_FUNC_3, PG8); /* RX: G; mux 2; func 3; PG8 */ |
| 183 | break; |
| 184 | case 1: |
| 185 | serial_early_do_mach_portmux('F', PORT_x_MUX_5_MASK, |
| 186 | PORT_x_MUX_5_FUNC_3, PF14); /* TX: F; mux 5; func 3; PF14 */ |
| 187 | serial_early_do_mach_portmux('F', PORT_x_MUX_5_MASK, |
| 188 | PORT_x_MUX_5_FUNC_3, PF15); /* RX: F; mux 5; func 3; PF15 */ |
| 189 | break; |
| 190 | } |
| 191 | #elif defined(__ADSPBF537__) || defined(__ADSPBF536__) || defined(__ADSPBF534__) |
| 192 | const uint16_t func[] = { PFDE, PFTE, }; |
| 193 | bfin_write_PORT_MUX(bfin_read_PORT_MUX() & ~func[CONFIG_UART_CONSOLE]); |
| 194 | bfin_write_PORTF_FER(bfin_read_PORTF_FER() | |
| 195 | (1 << P_IDENT(P_UART(RX))) | |
| 196 | (1 << P_IDENT(P_UART(TX)))); |
| 197 | #elif defined(__ADSPBF54x__) |
| 198 | switch (CONFIG_UART_CONSOLE) { |
| 199 | case 0: |
| 200 | serial_early_do_mach_portmux('E', PORT_x_MUX_7_MASK, |
| 201 | PORT_x_MUX_7_FUNC_1, PE7); /* TX: E; mux 7; func 1; PE7 */ |
| 202 | serial_early_do_mach_portmux('E', PORT_x_MUX_8_MASK, |
| 203 | PORT_x_MUX_8_FUNC_1, PE8); /* RX: E; mux 8; func 1; PE8 */ |
| 204 | break; |
| 205 | case 1: |
| 206 | serial_early_do_mach_portmux('H', PORT_x_MUX_0_MASK, |
| 207 | PORT_x_MUX_0_FUNC_1, PH0); /* TX: H; mux 0; func 1; PH0 */ |
| 208 | serial_early_do_mach_portmux('H', PORT_x_MUX_1_MASK, |
| 209 | PORT_x_MUX_1_FUNC_1, PH1); /* RX: H; mux 1; func 1; PH1 */ |
| 210 | break; |
| 211 | case 2: |
| 212 | serial_early_do_mach_portmux('B', PORT_x_MUX_4_MASK, |
| 213 | PORT_x_MUX_4_FUNC_1, PB4); /* TX: B; mux 4; func 1; PB4 */ |
| 214 | serial_early_do_mach_portmux('B', PORT_x_MUX_5_MASK, |
| 215 | PORT_x_MUX_5_FUNC_1, PB5); /* RX: B; mux 5; func 1; PB5 */ |
| 216 | break; |
| 217 | case 3: |
| 218 | serial_early_do_mach_portmux('B', PORT_x_MUX_6_MASK, |
| 219 | PORT_x_MUX_6_FUNC_1, PB6); /* TX: B; mux 6; func 1; PB6 */ |
| 220 | serial_early_do_mach_portmux('B', PORT_x_MUX_7_MASK, |
| 221 | PORT_x_MUX_7_FUNC_1, PB7); /* RX: B; mux 7; func 1; PB7 */ |
| 222 | break; |
| 223 | } |
| 224 | #elif defined(__ADSPBF561__) |
| 225 | /* UART pins could be GPIO, but they aren't pin muxed. */ |
| 226 | #else |
| 227 | # if (P_UART(RX) & P_DEFINED) || (P_UART(TX) & P_DEFINED) |
| 228 | # error "missing portmux logic for UART" |
| 229 | # endif |
| 230 | #endif |
| 231 | SSYNC(); |
| 232 | } |
| 233 | |
| 234 | __attribute__((always_inline)) |
Sonic Zhang | 7a91b9b | 2012-08-16 11:16:02 +0800 | [diff] [blame] | 235 | static inline int uart_init(uint32_t uart_base) |
| 236 | { |
| 237 | /* always enable UART -- avoids anomalies 05000309 and 05000350 */ |
| 238 | bfin_write(&pUART->gctl, UCEN); |
| 239 | |
| 240 | /* Set LCR to Word Lengh 8-bit word select */ |
| 241 | bfin_write(&pUART->lcr, WLS_8); |
| 242 | |
| 243 | SSYNC(); |
| 244 | |
| 245 | return 0; |
| 246 | } |
| 247 | |
| 248 | __attribute__((always_inline)) |
| 249 | static inline int serial_early_init(uint32_t uart_base) |
| 250 | { |
| 251 | /* handle portmux crap on different Blackfins */ |
| 252 | serial_do_portmux(); |
| 253 | |
| 254 | return uart_init(uart_base); |
| 255 | } |
| 256 | |
| 257 | __attribute__((always_inline)) |
| 258 | static inline int serial_early_uninit(uint32_t uart_base) |
| 259 | { |
| 260 | /* disable the UART by clearing UCEN */ |
| 261 | bfin_write(&pUART->gctl, 0); |
| 262 | |
| 263 | return 0; |
| 264 | } |
| 265 | |
| 266 | __attribute__((always_inline)) |
Sonic Zhang | c15c403 | 2013-02-05 19:10:34 +0800 | [diff] [blame] | 267 | static inline void serial_set_divisor(uint32_t uart_base, uint16_t divisor) |
Sonic Zhang | 7a91b9b | 2012-08-16 11:16:02 +0800 | [diff] [blame] | 268 | { |
Sonic Zhang | 7a91b9b | 2012-08-16 11:16:02 +0800 | [diff] [blame] | 269 | /* Set DLAB in LCR to Access DLL and DLH */ |
| 270 | ACCESS_LATCH(); |
| 271 | SSYNC(); |
| 272 | |
| 273 | /* Program the divisor to get the baud rate we want */ |
| 274 | bfin_write(&pUART->dll, LOB(divisor)); |
| 275 | bfin_write(&pUART->dlh, HIB(divisor)); |
| 276 | SSYNC(); |
| 277 | |
| 278 | /* Clear DLAB in LCR to Access THR RBR IER */ |
| 279 | ACCESS_PORT_IER(); |
| 280 | SSYNC(); |
| 281 | } |
| 282 | |
| 283 | __attribute__((always_inline)) |
Sonic Zhang | c15c403 | 2013-02-05 19:10:34 +0800 | [diff] [blame] | 284 | static inline void serial_early_set_baud(uint32_t uart_base, uint32_t baud) |
| 285 | { |
| 286 | /* Translate from baud into divisor in terms of SCLK. The |
| 287 | * weird multiplication is to make sure we over sample just |
| 288 | * a little rather than under sample the incoming signals. |
| 289 | */ |
Sonic Zhang | dbfad02 | 2012-11-30 17:39:32 +0800 | [diff] [blame] | 290 | #if CONFIG_BFIN_BOOT_MODE == BFIN_BOOT_BYPASS |
| 291 | uint16_t divisor = (early_get_uart_clk() + baud * 8) / (baud * 16) |
| 292 | - ANOMALY_05000230; |
| 293 | #else |
Sonic Zhang | c15c403 | 2013-02-05 19:10:34 +0800 | [diff] [blame] | 294 | uint16_t divisor = early_division(early_get_uart_clk() + (baud * 8), |
| 295 | baud * 16) - ANOMALY_05000230; |
Sonic Zhang | dbfad02 | 2012-11-30 17:39:32 +0800 | [diff] [blame] | 296 | #endif |
Sonic Zhang | c15c403 | 2013-02-05 19:10:34 +0800 | [diff] [blame] | 297 | |
| 298 | serial_set_divisor(uart_base, divisor); |
| 299 | } |
| 300 | |
| 301 | __attribute__((always_inline)) |
Sonic Zhang | 7a91b9b | 2012-08-16 11:16:02 +0800 | [diff] [blame] | 302 | static inline void serial_early_put_div(uint16_t divisor) |
| 303 | { |
| 304 | uint32_t uart_base = UART_BASE; |
| 305 | |
| 306 | /* Set DLAB in LCR to Access DLL and DLH */ |
| 307 | ACCESS_LATCH(); |
| 308 | SSYNC(); |
| 309 | |
| 310 | /* Program the divisor to get the baud rate we want */ |
| 311 | bfin_write(&pUART->dll, LOB(divisor)); |
| 312 | bfin_write(&pUART->dlh, HIB(divisor)); |
| 313 | SSYNC(); |
| 314 | |
| 315 | /* Clear DLAB in LCR to Access THR RBR IER */ |
| 316 | ACCESS_PORT_IER(); |
| 317 | SSYNC(); |
| 318 | } |
| 319 | |
| 320 | __attribute__((always_inline)) |
| 321 | static inline uint16_t serial_early_get_div(void) |
| 322 | { |
| 323 | uint32_t uart_base = UART_BASE; |
| 324 | |
| 325 | /* Set DLAB in LCR to Access DLL and DLH */ |
| 326 | ACCESS_LATCH(); |
| 327 | SSYNC(); |
| 328 | |
| 329 | uint8_t dll = bfin_read(&pUART->dll); |
| 330 | uint8_t dlh = bfin_read(&pUART->dlh); |
| 331 | uint16_t divisor = (dlh << 8) | dll; |
| 332 | |
| 333 | /* Clear DLAB in LCR to Access THR RBR IER */ |
| 334 | ACCESS_PORT_IER(); |
| 335 | SSYNC(); |
| 336 | |
| 337 | return divisor; |
| 338 | } |
| 339 | |
| 340 | #endif |
| 341 | |
| 342 | #endif |