blob: 0d6f377c058328ca8e875a5a3ee406a1c380c680 [file] [log] [blame]
Mike Frysinger9171fc82008-03-30 15:46:13 -04001/*
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>,
Wolfgang Denk53677ef2008-05-20 16:00:29 +02007 * BuyWays B.V. (www.buyways.nl)
Mike Frysinger9171fc82008-03-30 15:46:13 -04008 *
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#include <common.h>
28#include <watchdog.h>
29#include <asm/blackfin.h>
30#include <asm/mach-common/bits/uart.h>
31
32#if defined(UART_LSR) && (CONFIG_UART_CONSOLE != 0)
33# error CONFIG_UART_CONSOLE must be 0 on parts with only one UART
34#endif
35
36#include "serial.h"
37
Mike Frysingerf177f422008-04-09 02:02:07 -040038#ifdef CONFIG_DEBUG_SERIAL
39uint16_t cached_lsr[256];
40uint16_t cached_rbr[256];
41size_t cache_count;
42
43/* The LSR is read-to-clear on some parts, so we have to make sure status
44 * bits aren't inadvertently lost when doing various tests.
45 */
46static uint16_t uart_lsr_save;
47static uint16_t uart_lsr_read(void)
48{
49 uint16_t lsr = *pUART_LSR;
50 uart_lsr_save |= (lsr & (OE|PE|FE|BI));
51 return lsr | uart_lsr_save;
52}
53/* Just do the clear for everyone since it can't hurt. */
54static void uart_lsr_clear(void)
55{
56 uart_lsr_save = 0;
57 *pUART_LSR |= -1;
58}
59#else
60static inline uint16_t uart_lsr_read(void) { return *pUART_LSR; }
61static inline void uart_lsr_clear(void) { *pUART_LSR = -1; }
62#endif
63
Mike Frysinger9171fc82008-03-30 15:46:13 -040064/* Symbol for our assembly to call. */
65void serial_set_baud(uint32_t baud)
66{
67 serial_early_set_baud(baud);
68}
69
70/* Symbol for common u-boot code to call.
71 * Setup the baudrate (brg: baudrate generator).
72 */
73void serial_setbrg(void)
74{
75 DECLARE_GLOBAL_DATA_PTR;
76 serial_set_baud(gd->baudrate);
77}
78
79/* Symbol for our assembly to call. */
80void serial_initialize(void)
81{
82 serial_early_init();
83}
84
85/* Symbol for common u-boot code to call. */
86int serial_init(void)
87{
88 serial_initialize();
89 serial_setbrg();
Mike Frysingerf177f422008-04-09 02:02:07 -040090 uart_lsr_clear();
91#ifdef CONFIG_DEBUG_SERIAL
92 cache_count = 0;
93 memset(cached_lsr, 0x00, sizeof(cached_lsr));
94 memset(cached_rbr, 0x00, sizeof(cached_rbr));
95#endif
Mike Frysinger9171fc82008-03-30 15:46:13 -040096 return 0;
97}
98
99void serial_putc(const char c)
100{
101 /* send a \r for compatibility */
102 if (c == '\n')
103 serial_putc('\r');
104
105 WATCHDOG_RESET();
106
107 /* wait for the hardware fifo to clear up */
Mike Frysingerf177f422008-04-09 02:02:07 -0400108 while (!(uart_lsr_read() & THRE))
Mike Frysinger9171fc82008-03-30 15:46:13 -0400109 continue;
110
111 /* queue the character for transmission */
112 *pUART_THR = c;
113 SSYNC();
114
115 WATCHDOG_RESET();
116
117 /* wait for the byte to be shifted over the line */
Mike Frysingerf177f422008-04-09 02:02:07 -0400118 while (!(uart_lsr_read() & TEMT))
Mike Frysinger9171fc82008-03-30 15:46:13 -0400119 continue;
120}
121
122int serial_tstc(void)
123{
124 WATCHDOG_RESET();
Mike Frysingerf177f422008-04-09 02:02:07 -0400125 return (uart_lsr_read() & DR) ? 1 : 0;
Mike Frysinger9171fc82008-03-30 15:46:13 -0400126}
127
128int serial_getc(void)
129{
Mike Frysingerf177f422008-04-09 02:02:07 -0400130 uint16_t uart_rbr_val;
Mike Frysinger9171fc82008-03-30 15:46:13 -0400131
132 /* wait for data ! */
133 while (!serial_tstc())
134 continue;
135
Mike Frysingerf177f422008-04-09 02:02:07 -0400136 /* grab the new byte */
Mike Frysinger9171fc82008-03-30 15:46:13 -0400137 uart_rbr_val = *pUART_RBR;
138
Mike Frysingerf177f422008-04-09 02:02:07 -0400139#ifdef CONFIG_DEBUG_SERIAL
140 /* grab & clear the LSR */
141 uint16_t uart_lsr_val = uart_lsr_read();
142
143 cached_lsr[cache_count] = uart_lsr_val;
144 cached_rbr[cache_count] = uart_rbr_val;
145 cache_count = (cache_count + 1) % ARRAY_SIZE(cached_lsr);
146
Mike Frysinger9171fc82008-03-30 15:46:13 -0400147 if (uart_lsr_val & (OE|PE|FE|BI)) {
Mike Frysingerf177f422008-04-09 02:02:07 -0400148 uint16_t dll, dlh;
149 printf("\n[SERIAL ERROR]\n");
150 ACCESS_LATCH();
151 dll = *pUART_DLL;
152 dlh = *pUART_DLH;
153 ACCESS_PORT_IER();
154 printf("\tDLL=0x%x DLH=0x%x\n", dll, dlh);
155 do {
156 --cache_count;
157 printf("\t%3i: RBR=0x%02x LSR=0x%02x\n", cache_count,
158 cached_rbr[cache_count], cached_lsr[cache_count]);
159 } while (cache_count > 0);
Mike Frysinger9171fc82008-03-30 15:46:13 -0400160 return -1;
161 }
Mike Frysingerf177f422008-04-09 02:02:07 -0400162#endif
163 uart_lsr_clear();
Mike Frysinger9171fc82008-03-30 15:46:13 -0400164
Mike Frysingerf177f422008-04-09 02:02:07 -0400165 return uart_rbr_val;
Mike Frysinger9171fc82008-03-30 15:46:13 -0400166}
167
168void serial_puts(const char *s)
169{
170 while (*s)
171 serial_putc(*s++);
172}