uboot/cpu/blackfin/serial.c
<<
>>
Prefs
   1/*
   2 * U-boot - serial.c Blackfin Serial Driver
   3 *
   4 * Copyright (c) 2005-2008 Analog Devices Inc.
   5 *
   6 * Copyright (c) 2003   Bas Vermeulen <bas@buyways.nl>,
   7 *                      BuyWays B.V. (www.buyways.nl)
   8 *
   9 * Based heavily on:
  10 * blkfinserial.c: Serial driver for BlackFin DSP internal USRTs.
  11 * Copyright(c) 2003    Metrowerks      <mwaddel@metrowerks.com>
  12 * Copyright(c) 2001    Tony Z. Kou     <tonyko@arcturusnetworks.com>
  13 * Copyright(c) 2001-2002 Arcturus Networks Inc. <www.arcturusnetworks.com>
  14 *
  15 * Based on code from 68328 version serial driver imlpementation which was:
  16 * Copyright (C) 1995       David S. Miller    <davem@caip.rutgers.edu>
  17 * Copyright (C) 1998       Kenneth Albanowski <kjahds@kjahds.com>
  18 * Copyright (C) 1998, 1999 D. Jeff Dionne     <jeff@uclinux.org>
  19 * Copyright (C) 1999       Vladimir Gurevich  <vgurevic@cisco.com>
  20 *
  21 * (C) Copyright 2000-2004
  22 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
  23 *
  24 * Licensed under the GPL-2 or later.
  25 */
  26
  27/* Anomaly notes:
  28 *  05000086 - we don't support autobaud
  29 *  05000099 - we only use DR bit, so losing others is not a problem
  30 *  05000100 - we don't use the UART_IIR register
  31 *  05000215 - we poll the uart (no dma/interrupts)
  32 *  05000225 - no workaround possible, but this shouldnt cause errors ...
  33 *  05000230 - we tweak the baud rate calculation slightly
  34 *  05000231 - we always use 1 stop bit
  35 *  05000309 - we always enable the uart before we modify it in anyway
  36 *  05000350 - we always enable the uart regardless of boot mode
  37 *  05000363 - we don't support break signals, so don't generate one
  38 */
  39
  40#include <common.h>
  41#include <watchdog.h>
  42#include <asm/blackfin.h>
  43#include <asm/mach-common/bits/uart.h>
  44
  45#ifdef CONFIG_UART_CONSOLE
  46
  47#if defined(UART_LSR) && (CONFIG_UART_CONSOLE != 0)
  48# error CONFIG_UART_CONSOLE must be 0 on parts with only one UART
  49#endif
  50
  51#include "serial.h"
  52
  53#ifdef CONFIG_DEBUG_SERIAL
  54uint16_t cached_lsr[256];
  55uint16_t cached_rbr[256];
  56size_t cache_count;
  57
  58/* The LSR is read-to-clear on some parts, so we have to make sure status
  59 * bits aren't inadvertently lost when doing various tests.  This also
  60 * works around anomaly 05000099 at the same time by keeping a cumulative
  61 * tally of all the status bits.
  62 */
  63static uint16_t uart_lsr_save;
  64static uint16_t uart_lsr_read(void)
  65{
  66        uint16_t lsr = *pUART_LSR;
  67        uart_lsr_save |= (lsr & (OE|PE|FE|BI));
  68        return lsr | uart_lsr_save;
  69}
  70/* Just do the clear for everyone since it can't hurt. */
  71static void uart_lsr_clear(void)
  72{
  73        uart_lsr_save = 0;
  74        *pUART_LSR |= -1;
  75}
  76#else
  77/* When debugging is disabled, we only care about the DR bit, so if other
  78 * bits get set/cleared, we don't really care since we don't read them
  79 * anyways (and thus anomaly 05000099 is irrelevant).
  80 */
  81static inline uint16_t uart_lsr_read(void) { return *pUART_LSR; }
  82static inline void uart_lsr_clear(void) { *pUART_LSR = -1; }
  83#endif
  84
  85/* Symbol for our assembly to call. */
  86void serial_set_baud(uint32_t baud)
  87{
  88        serial_early_set_baud(baud);
  89}
  90
  91/* Symbol for common u-boot code to call.
  92 * Setup the baudrate (brg: baudrate generator).
  93 */
  94void serial_setbrg(void)
  95{
  96        DECLARE_GLOBAL_DATA_PTR;
  97        serial_set_baud(gd->baudrate);
  98}
  99
 100/* Symbol for our assembly to call. */
 101void serial_initialize(void)
 102{
 103        serial_early_init();
 104}
 105
 106/* Symbol for common u-boot code to call. */
 107int serial_init(void)
 108{
 109        serial_initialize();
 110        serial_setbrg();
 111        uart_lsr_clear();
 112#ifdef CONFIG_DEBUG_SERIAL
 113        cache_count = 0;
 114        memset(cached_lsr, 0x00, sizeof(cached_lsr));
 115        memset(cached_rbr, 0x00, sizeof(cached_rbr));
 116#endif
 117        return 0;
 118}
 119
 120void serial_putc(const char c)
 121{
 122        /* send a \r for compatibility */
 123        if (c == '\n')
 124                serial_putc('\r');
 125
 126        WATCHDOG_RESET();
 127
 128        /* wait for the hardware fifo to clear up */
 129        while (!(uart_lsr_read() & THRE))
 130                continue;
 131
 132        /* queue the character for transmission */
 133        *pUART_THR = c;
 134        SSYNC();
 135
 136        WATCHDOG_RESET();
 137}
 138
 139int serial_tstc(void)
 140{
 141        WATCHDOG_RESET();
 142        return (uart_lsr_read() & DR) ? 1 : 0;
 143}
 144
 145int serial_getc(void)
 146{
 147        uint16_t uart_rbr_val;
 148
 149        /* wait for data ! */
 150        while (!serial_tstc())
 151                continue;
 152
 153        /* grab the new byte */
 154        uart_rbr_val = *pUART_RBR;
 155
 156#ifdef CONFIG_DEBUG_SERIAL
 157        /* grab & clear the LSR */
 158        uint16_t uart_lsr_val = uart_lsr_read();
 159
 160        cached_lsr[cache_count] = uart_lsr_val;
 161        cached_rbr[cache_count] = uart_rbr_val;
 162        cache_count = (cache_count + 1) % ARRAY_SIZE(cached_lsr);
 163
 164        if (uart_lsr_val & (OE|PE|FE|BI)) {
 165                uint16_t dll, dlh;
 166                printf("\n[SERIAL ERROR]\n");
 167                ACCESS_LATCH();
 168                dll = *pUART_DLL;
 169                dlh = *pUART_DLH;
 170                ACCESS_PORT_IER();
 171                printf("\tDLL=0x%x DLH=0x%x\n", dll, dlh);
 172                do {
 173                        --cache_count;
 174                        printf("\t%3i: RBR=0x%02x LSR=0x%02x\n", cache_count,
 175                                cached_rbr[cache_count], cached_lsr[cache_count]);
 176                } while (cache_count > 0);
 177                return -1;
 178        }
 179#endif
 180        uart_lsr_clear();
 181
 182        return uart_rbr_val;
 183}
 184
 185void serial_puts(const char *s)
 186{
 187        while (*s)
 188                serial_putc(*s++);
 189}
 190
 191#endif
 192