uboot/cpu/blackfin/serial.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-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
  17#ifndef CONFIG_UART_CONSOLE
  18# define CONFIG_UART_CONSOLE 0
  19#endif
  20
  21#ifdef CONFIG_DEBUG_EARLY_SERIAL
  22# define BFIN_DEBUG_EARLY_SERIAL 1
  23#else
  24# define BFIN_DEBUG_EARLY_SERIAL 0
  25#endif
  26
  27#define LOB(x) ((x) & 0xFF)
  28#define HIB(x) (((x) >> 8) & 0xFF)
  29
  30#ifndef UART_LSR
  31# if (CONFIG_UART_CONSOLE == 3)
  32#  define pUART_DLH  pUART3_DLH
  33#  define pUART_DLL  pUART3_DLL
  34#  define pUART_GCTL pUART3_GCTL
  35#  define pUART_IER  pUART3_IER
  36#  define pUART_IERC pUART3_IER_CLEAR
  37#  define pUART_LCR  pUART3_LCR
  38#  define pUART_LSR  pUART3_LSR
  39#  define pUART_RBR  pUART3_RBR
  40#  define pUART_THR  pUART3_THR
  41#  define  UART_THR   UART3_THR
  42#  define  UART_LSR   UART3_LSR
  43# elif (CONFIG_UART_CONSOLE == 2)
  44#  define pUART_DLH  pUART2_DLH
  45#  define pUART_DLL  pUART2_DLL
  46#  define pUART_GCTL pUART2_GCTL
  47#  define pUART_IER  pUART2_IER
  48#  define pUART_IERC pUART2_IER_CLEAR
  49#  define pUART_LCR  pUART2_LCR
  50#  define pUART_LSR  pUART2_LSR
  51#  define pUART_RBR  pUART2_RBR
  52#  define pUART_THR  pUART2_THR
  53#  define  UART_THR   UART2_THR
  54#  define  UART_LSR   UART2_LSR
  55# elif (CONFIG_UART_CONSOLE == 1)
  56#  define pUART_DLH  pUART1_DLH
  57#  define pUART_DLL  pUART1_DLL
  58#  define pUART_GCTL pUART1_GCTL
  59#  define pUART_IER  pUART1_IER
  60#  define pUART_IERC pUART1_IER_CLEAR
  61#  define pUART_LCR  pUART1_LCR
  62#  define pUART_LSR  pUART1_LSR
  63#  define pUART_RBR  pUART1_RBR
  64#  define pUART_THR  pUART1_THR
  65#  define  UART_THR   UART1_THR
  66#  define  UART_LSR   UART1_LSR
  67# elif (CONFIG_UART_CONSOLE == 0)
  68#  define pUART_DLH  pUART0_DLH
  69#  define pUART_DLL  pUART0_DLL
  70#  define pUART_GCTL pUART0_GCTL
  71#  define pUART_IER  pUART0_IER
  72#  define pUART_IERC pUART0_IER_CLEAR
  73#  define pUART_LCR  pUART0_LCR
  74#  define pUART_LSR  pUART0_LSR
  75#  define pUART_RBR  pUART0_RBR
  76#  define pUART_THR  pUART0_THR
  77#  define  UART_THR   UART0_THR
  78#  define  UART_LSR   UART0_LSR
  79# endif
  80#endif
  81
  82#ifndef __ASSEMBLY__
  83
  84#ifdef __ADSPBF54x__
  85# define ACCESS_LATCH()
  86# define ACCESS_PORT_IER()
  87# define CLEAR_IER()       (*pUART_IERC = 0)
  88#else
  89# define ACCESS_LATCH()    (*pUART_LCR |= DLAB)
  90# define ACCESS_PORT_IER() (*pUART_LCR &= ~DLAB)
  91# define CLEAR_IER()       (*pUART_IER = 0)
  92#endif
  93
  94__attribute__((always_inline))
  95static inline void serial_do_portmux(void)
  96{
  97#if defined(__ADSPBF51x__)
  98# define DO_MUX(port, mux_tx, mux_rx, tx, rx) \
  99        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); \
 100        bfin_write_PORT##port##_FER(bfin_read_PORT##port##_FER() | P##port##tx | P##port##rx);
 101        switch (CONFIG_UART_CONSOLE) {
 102        case 0: DO_MUX(G, 5, 5, 9, 10);  break; /* Port G; mux 5; PG9 and PG10 */
 103        case 1: DO_MUX(F, 2, 3, 14, 15); break; /* Port H; mux 2/3; PH14 and PH15 */
 104        }
 105        SSYNC();
 106#elif defined(__ADSPBF52x__)
 107# define DO_MUX(port, mux, tx, rx) \
 108        bfin_write_PORT##port##_MUX((bfin_read_PORT##port##_MUX() & ~PORT_x_MUX_##mux##_MASK) | PORT_x_MUX_##mux##_FUNC_3); \
 109        bfin_write_PORT##port##_FER(bfin_read_PORT##port##_FER() | P##port##tx | P##port##rx);
 110        switch (CONFIG_UART_CONSOLE) {
 111        case 0: DO_MUX(G, 2, 7, 8);   break;    /* Port G; mux 2; PG2 and PG8 */
 112        case 1: DO_MUX(F, 5, 14, 15); break;    /* Port F; mux 5; PF14 and PF15 */
 113        }
 114        SSYNC();
 115#elif defined(__ADSPBF537__) || defined(__ADSPBF536__) || defined(__ADSPBF534__)
 116# define DO_MUX(func, tx, rx) \
 117        bfin_write_PORT_MUX(bfin_read_PORT_MUX() & ~(func)); \
 118        bfin_write_PORTF_FER(bfin_read_PORTF_FER() | PF##tx | PF##rx);
 119        switch (CONFIG_UART_CONSOLE) {
 120        case 0: DO_MUX(PFDE, 0, 1); break;
 121        case 1: DO_MUX(PFTE, 2, 3); break;
 122        }
 123        SSYNC();
 124#elif defined(__ADSPBF54x__)
 125# define DO_MUX(port, tx, rx) \
 126        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); \
 127        bfin_write_PORT##port##_FER(bfin_read_PORT##port##_FER() | P##port##tx | P##port##rx);
 128        switch (CONFIG_UART_CONSOLE) {
 129        case 0: DO_MUX(E, 7, 8); break; /* Port E; PE7 and PE8 */
 130        case 1: DO_MUX(H, 0, 1); break; /* Port H; PH0 and PH1 */
 131        case 2: DO_MUX(B, 4, 5); break; /* Port B; PB4 and PB5 */
 132        case 3: DO_MUX(B, 6, 7); break; /* Port B; PB6 and PB7 */
 133        }
 134        SSYNC();
 135#endif
 136}
 137
 138__attribute__((always_inline))
 139static inline void serial_early_init(void)
 140{
 141        /* handle portmux crap on different Blackfins */
 142        serial_do_portmux();
 143
 144        /* always enable UART -- avoids anomalies 05000309 and 05000350 */
 145        *pUART_GCTL = UCEN;
 146
 147        /* Set LCR to Word Lengh 8-bit word select */
 148        *pUART_LCR = WLS_8;
 149
 150        SSYNC();
 151}
 152
 153__attribute__((always_inline))
 154static inline void serial_early_put_div(uint16_t divisor)
 155{
 156        /* Set DLAB in LCR to Access DLL and DLH */
 157        ACCESS_LATCH();
 158        SSYNC();
 159
 160        /* Program the divisor to get the baud rate we want */
 161        *pUART_DLL = LOB(divisor);
 162        *pUART_DLH = HIB(divisor);
 163        SSYNC();
 164
 165        /* Clear DLAB in LCR to Access THR RBR IER */
 166        ACCESS_PORT_IER();
 167        SSYNC();
 168}
 169
 170__attribute__((always_inline))
 171static inline uint16_t serial_early_get_div(void)
 172{
 173        /* Set DLAB in LCR to Access DLL and DLH */
 174        ACCESS_LATCH();
 175        SSYNC();
 176
 177        uint8_t dll = *pUART_DLL;
 178        uint8_t dlh = *pUART_DLH;
 179        uint16_t divisor = (dlh << 8) | dll;
 180
 181        /* Clear DLAB in LCR to Access THR RBR IER */
 182        ACCESS_PORT_IER();
 183        SSYNC();
 184
 185        return divisor;
 186}
 187
 188/* We cannot use get_sclk() early on as it uses caches in external memory */
 189#if defined(BFIN_IN_INITCODE) || defined(CONFIG_DEBUG_EARLY_SERIAL)
 190# define get_sclk() (CONFIG_CLKIN_HZ * CONFIG_VCO_MULT / CONFIG_SCLK_DIV)
 191#endif
 192
 193__attribute__((always_inline))
 194static inline void serial_early_set_baud(uint32_t baud)
 195{
 196        /* Translate from baud into divisor in terms of SCLK.  The
 197         * weird multiplication is to make sure we over sample just
 198         * a little rather than under sample the incoming signals.
 199         */
 200        serial_early_put_div((get_sclk() + (baud * 8)) / (baud * 16) - ANOMALY_05000230);
 201}
 202
 203#ifndef BFIN_IN_INITCODE
 204__attribute__((always_inline))
 205static inline void serial_early_puts(const char *s)
 206{
 207        if (BFIN_DEBUG_EARLY_SERIAL) {
 208                serial_puts("Early: ");
 209                serial_puts(s);
 210        }
 211}
 212#endif
 213
 214#else
 215
 216.macro serial_early_init
 217#ifdef CONFIG_DEBUG_EARLY_SERIAL
 218        call _serial_initialize;
 219#endif
 220.endm
 221
 222.macro serial_early_set_baud
 223#ifdef CONFIG_DEBUG_EARLY_SERIAL
 224        R0.L = LO(CONFIG_BAUDRATE);
 225        R0.H = HI(CONFIG_BAUDRATE);
 226        call _serial_set_baud;
 227#endif
 228.endm
 229
 230/* Since we embed the string right into our .text section, we need
 231 * to find its address.  We do this by getting our PC and adding 2
 232 * bytes (which is the length of the jump instruction).  Then we
 233 * pass this address to serial_puts().
 234 */
 235#ifdef CONFIG_DEBUG_EARLY_SERIAL
 236# define serial_early_puts(str) \
 237        call _get_pc; \
 238        jump 1f; \
 239        .ascii "Early:"; \
 240        .ascii __FILE__; \
 241        .ascii ": "; \
 242        .ascii str; \
 243        .asciz "\n"; \
 244        .align 4; \
 2451: \
 246        R0 += 2; \
 247        call _serial_puts;
 248#else
 249# define serial_early_puts(str)
 250#endif
 251
 252#endif
 253
 254#endif
 255