3 * \brief PXA UART implementation
6 * \author Adam Lackorznynski <adam@os.inf.tu-dresden.de>
7 * Alexander Warg <alexander.warg@os.inf.tu-dresden.de>
11 * (c) 2008-2009 Author(s)
12 * economic rights: Technische Universität Dresden (Germany)
14 * This file is part of TUD:OS and distributed under the terms of the
15 * GNU General Public License 2.
16 * Please see the COPYING-GPL-2 file for details.
19 #include "poll_timeout_counter.h"
25 TRB = 0x00, // Transmit/Receive Buffer (read/write)
26 BRD_LOW = 0x00, // Baud Rate Divisor LSB if bit 7 of LCR is set (read/write)
27 IER = 0x01, // Interrupt Enable Register (read/write)
28 BRD_HIGH = 0x01, // Baud Rate Divisor MSB if bit 7 of LCR is set (read/write)
29 IIR = 0x02, // Interrupt Identification Register (read only)
30 FCR = 0x02, // 16550 FIFO Control Register (write only)
31 LCR = 0x03, // Line Control Register (read/write)
32 MCR = 0x04, // Modem Control Register (read/write)
33 LSR = 0x05, // Line Status Register (read only)
34 MSR = 0x06, // Modem Status Register (read only)
35 SPR = 0x07, // Scratch Pad Register (read/write)
40 Base_ier_bits = 1 << 6, // pxa only?
43 bool Uart_16550::startup(Io_register_block const *regs)
47 char scratch, scratch2, scratch3;
49 scratch = _regs->read<unsigned char>(IER);
50 _regs->write<unsigned char>(IER, 0);
54 scratch2 = _regs->read<unsigned char>(IER);
55 _regs->write<unsigned char>(IER, 0xf);
59 scratch3 = _regs->read<unsigned char>(IER);
60 _regs->write<unsigned char>(IER, scratch);
62 if (!(scratch2 == 0x00 && scratch3 == 0x0f))
63 return false; // this is not the uart
65 _regs->write<unsigned char>(IER, Base_ier_bits);/* disable all rs-232 interrupts */
66 _regs->write<unsigned char>(MCR, 0xb); /* out2, rts, and dtr enabled */
67 _regs->write<unsigned char>(FCR, 1); /* enable fifo */
68 _regs->write<unsigned char>(FCR, 7); /* clear rcv xmit fifo */
69 _regs->write<unsigned char>(FCR, 1); /* enable fifo */
70 _regs->write<unsigned char>(LCR, 0); /* clear line control register */
72 /* clearall interrupts */
73 _regs->read<unsigned char>(MSR); /* IRQID 0*/
74 _regs->read<unsigned char>(IIR); /* IRQID 1*/
75 _regs->read<unsigned char>(TRB); /* IRQID 2*/
76 _regs->read<unsigned char>(LSR); /* IRQID 3*/
78 Poll_timeout_counter i(5000000);
79 while (i.test(_regs->read<unsigned char>(LSR) & 1/*DATA READY*/))
80 _regs->read<unsigned char>(TRB);
85 void Uart_16550::shutdown()
87 _regs->write<unsigned char>(MCR, 6);
88 _regs->write<unsigned char>(FCR, 0);
89 _regs->write<unsigned char>(LCR, 0);
90 _regs->write<unsigned char>(IER, 0);
93 bool Uart_16550::change_mode(Transfer_mode m, Baud_rate r)
95 unsigned long old_lcr = _regs->read<unsigned char>(LCR);
97 unsigned short divisor = _base_rate / r;
98 _regs->write<unsigned char>(LCR, old_lcr | 0x80/*DLAB*/);
99 _regs->write<unsigned char>(TRB, divisor & 0x0ff); /* BRD_LOW */
100 _regs->write<unsigned char>(IER, (divisor >> 8) & 0x0ff); /* BRD_HIGH */
101 _regs->write<unsigned char>(LCR, old_lcr);
104 _regs->write<unsigned char>(LCR, m & 0x07f);
109 int Uart_16550::get_char(bool blocking) const
113 if (!blocking && !char_avail())
116 old_ier = _regs->read<unsigned char>(IER);
117 _regs->write<unsigned char>(IER, old_ier & ~0xf);
118 while (!char_avail())
120 ch = _regs->read<unsigned char>(TRB);
121 _regs->write<unsigned char>(IER, old_ier);
125 int Uart_16550::char_avail() const
127 return _regs->read<unsigned char>(LSR) & 1; // DATA READY
130 void Uart_16550::out_char(char c) const
135 int Uart_16550::write(char const *s, unsigned long count) const
137 /* disable uart irqs */
140 old_ier = _regs->read<unsigned char>(IER);
141 _regs->write<unsigned char>(IER, old_ier & ~0x0f);
144 Poll_timeout_counter cnt(5000000);
145 for (i = 0; i < count; i++) {
147 while (cnt.test(!(_regs->read<unsigned char>(LSR) & 0x20 /* THRE */)))
149 _regs->write<unsigned char>(TRB, s[i]);
152 /* wait till everything is transmitted */
154 while (cnt.test(!(_regs->read<unsigned char>(LSR) & 0x40 /* TSRE */)))
157 _regs->write<unsigned char>(IER, old_ier);