uboot/arch/blackfin/include/asm/serial1.h
<<
>>
Prefs
   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#include <asm/clock.h>
  19
  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 */
  36struct 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))
 105static 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))
 144static 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))
 235static 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))
 249static 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))
 258static 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))
 267static inline void serial_set_divisor(uint32_t uart_base, uint16_t divisor)
 268{
 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))
 284static 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#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
 294        uint16_t divisor = early_division(early_get_uart_clk() + (baud * 8),
 295                        baud * 16) - ANOMALY_05000230;
 296#endif
 297
 298        serial_set_divisor(uart_base, divisor);
 299}
 300
 301__attribute__((always_inline))
 302static 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))
 321static 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
 343