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