]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/drivers-frst/uart/src/uart_pxa.cc
8dae9e384c6cbaf7affce430c345a4ccbc33ec16
[l4.git] / l4 / pkg / drivers-frst / uart / src / uart_pxa.cc
1 /*!
2  * \file   uart_pxa.cc
3  * \brief  PXA UART implementation
4  *
5  * \date   2008-01-04
6  * \author Adam Lackorznynski <adam@os.inf.tu-dresden.de>
7  *         Alexander Warg <alexander.warg@os.inf.tu-dresden.de>
8  *
9  */
10 /*
11  * (c) 2008-2009 Author(s)
12  *     economic rights: Technische Universität Dresden (Germany)
13  *
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.
17  */
18 #include "uart_pxa.h"
19 #include "poll_timeout_counter.h"
20
21 namespace L4
22 {
23   enum Registers
24   {
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)
36   };
37
38   enum
39   {
40     Base_ier_bits = 1 << 6, // pxa only?
41   };
42
43   bool Uart_16550::startup(Io_register_block const *regs)
44   {
45     _regs = regs;
46
47     char scratch, scratch2, scratch3;
48
49     scratch = _regs->read<unsigned char>(IER);
50     _regs->write<unsigned char>(IER, 0);
51
52     _regs->delay();
53
54     scratch2 = _regs->read<unsigned char>(IER);
55     _regs->write<unsigned char>(IER, 0xf);
56
57     _regs->delay();
58
59     scratch3 = _regs->read<unsigned char>(IER);
60     _regs->write<unsigned char>(IER, scratch);
61
62     if (!(scratch2 == 0x00 && scratch3 == 0x0f))
63       return false;  // this is not the uart
64
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 */
71
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*/
77
78     Poll_timeout_counter i(5000000);
79     while (i.test(_regs->read<unsigned char>(LSR) & 1/*DATA READY*/))
80       _regs->read<unsigned char>(TRB);
81
82     return true;
83   }
84
85   void Uart_16550::shutdown()
86   {
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);
91   }
92
93   bool Uart_16550::change_mode(Transfer_mode m, Baud_rate r)
94   {
95     unsigned long old_lcr = _regs->read<unsigned char>(LCR);
96     if(r != BAUD_NC) {
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);
102     }
103     if (m != MODE_NC)
104       _regs->write<unsigned char>(LCR, m & 0x07f);
105
106     return true;
107   }
108
109   int Uart_16550::get_char(bool blocking) const
110   {
111     char old_ier, ch;
112
113     if (!blocking && !char_avail())
114       return -1;
115
116     old_ier = _regs->read<unsigned char>(IER);
117     _regs->write<unsigned char>(IER, old_ier & ~0xf);
118     while (!char_avail())
119       ;
120     ch = _regs->read<unsigned char>(TRB);
121     _regs->write<unsigned char>(IER, old_ier);
122     return ch;
123   }
124
125   int Uart_16550::char_avail() const
126   {
127     return _regs->read<unsigned char>(LSR) & 1; // DATA READY
128   }
129
130   void Uart_16550::out_char(char c) const
131   {
132     write(&c, 1);
133   }
134
135   int Uart_16550::write(char const *s, unsigned long count) const
136   {
137     /* disable uart irqs */
138     char old_ier;
139     unsigned i;
140     old_ier = _regs->read<unsigned char>(IER);
141     _regs->write<unsigned char>(IER, old_ier & ~0x0f);
142
143     /* transmission */
144     Poll_timeout_counter cnt(5000000);
145     for (i = 0; i < count; i++) {
146       cnt.set(5000000);
147       while (cnt.test(!(_regs->read<unsigned char>(LSR) & 0x20 /* THRE */)))
148         ;
149       _regs->write<unsigned char>(TRB, s[i]);
150     }
151
152     /* wait till everything is transmitted */
153     cnt.set(5000000);
154     while (cnt.test(!(_regs->read<unsigned char>(LSR) & 0x40 /* TSRE */)))
155       ;
156
157     _regs->write<unsigned char>(IER, old_ier);
158     return count;
159   }
160 };