]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/drivers-frst/uart/src/uart_pxa.cc
update
[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
20 namespace L4
21 {
22   enum Registers {
23     TRB      = 0x00, // Transmit/Receive Buffer  (read/write)
24     BRD_LOW  = 0x00, // Baud Rate Divisor LSB if bit 7 of LCR is set  (read/write)
25     IER      = 0x04, // Interrupt Enable Register  (read/write)
26     BRD_HIGH = 0x04, // Baud Rate Divisor MSB if bit 7 of LCR is set  (read/write)
27     IIR      = 0x08, // Interrupt Identification Register  (read only)
28     FCR      = 0x08, // 16550 FIFO Control Register  (write only)
29     LCR      = 0x0c, // Line Control Register  (read/write)
30     MCR      = 0x10, // Modem Control Register  (read/write)
31     LSR      = 0x14, // Line Status Register  (read only)
32     MSR      = 0x18, // Modem Status Register  (read only)
33     SPR      = 0x1c, // Scratch Pad Register  (read/write)
34   };
35
36   enum {
37     Base_rate     = 921600,
38     Base_ier_bits = 1 << 6,
39   };
40
41   enum {
42     PAR_NONE = 0x00,
43     PAR_EVEN = 0x18,
44     PAR_ODD  = 0x08,
45     DAT_5    = 0x00,
46     DAT_6    = 0x01,
47     DAT_7    = 0x02,
48     DAT_8    = 0x03,
49     STOP_1   = 0x00,
50     STOP_2   = 0x04,
51
52     MODE_8N1 = PAR_NONE | DAT_8 | STOP_1,
53     MODE_7E1 = PAR_EVEN | DAT_7 | STOP_1,
54
55     // these two values are to leave either mode
56     // or baud rate unchanged on a call to change_mode
57     MODE_NC  = 0x1000000,
58     BAUD_NC  = 0x1000000,
59   };
60
61   unsigned long Uart_pxa::rd(unsigned long reg) const
62   { return *(volatile unsigned long*)(_base + reg); }
63
64   void Uart_pxa::wr(unsigned long reg, unsigned long val) const
65   { *(volatile unsigned long*)(_base + reg) = val; }
66
67   bool Uart_pxa::startup(unsigned long base)
68   {
69     _base = base;
70
71     char scratch, scratch2, scratch3;
72
73     scratch = rd(IER);
74     wr(IER, 0);
75
76     scratch2 = rd(IER);
77     wr(IER, 0xf);
78
79     scratch3 = rd(IER);
80     wr(IER, scratch);
81
82     if (!(scratch2 == 0x00 && scratch3 == 0x0f))
83       return false;  // this is not the uart
84
85     //proc_status o = proc_cli_save();
86     wr(IER, Base_ier_bits);/* disable all rs-232 interrupts */
87     wr(MCR, 0x0b);         /* out2, rts, and dtr enabled */
88     wr(FCR, 1);            /* enable fifo */
89     wr(FCR, 0x07);         /* clear rcv xmit fifo */
90     wr(FCR, 1);            /* enable fifo */
91     wr(LCR, 0);            /* clear line control register */
92
93     /* clearall interrupts */
94     /*read*/ rd(MSR); /* IRQID 0*/
95     /*read*/ rd(IIR); /* IRQID 1*/
96     /*read*/ rd(TRB); /* IRQID 2*/
97     /*read*/ rd(LSR); /* IRQID 3*/
98
99     while (rd(LSR) & 1/*DATA READY*/)
100       /*read*/ rd(TRB);
101     //proc_sti_restore(o);
102
103     return true;
104   }
105
106   void Uart_pxa::shutdown()
107   {
108     //proc_status o = proc_cli_save();
109     wr(MCR, 6);
110     wr(FCR, 0);
111     wr(LCR, 0);
112     wr(IER, 0);
113     //proc_sti_restore(o);
114   }
115
116   bool Uart_pxa::enable_rx_irq(bool /*enable*/) { return true; }
117   bool Uart_pxa::enable_tx_irq(bool /*enable*/) { return false; }
118   bool Uart_pxa::change_mode(Transfer_mode m, Baud_rate r)
119   {
120     //proc_status o = proc_cli_save();
121     unsigned long old_lcr = rd(LCR);
122     if(r != BAUD_NC) {
123       unsigned short divisor = Base_rate / r;
124       wr(LCR, old_lcr | 0x80/*DLAB*/);
125       wr(TRB, divisor & 0x0ff );        /* BRD_LOW  */
126       wr(IER, (divisor >> 8) & 0x0ff ); /* BRD_HIGH */
127       wr(LCR, old_lcr);
128     }
129     if (m != MODE_NC)
130       wr(LCR, m & 0x07f);
131
132     //proc_sti_restore(o);
133     return true;
134   }
135
136   int Uart_pxa::get_char(bool blocking) const
137   {
138     char old_ier, ch;
139
140     if (!blocking && !char_avail())
141       return -1;
142
143     old_ier = rd(IER);
144     wr(IER, old_ier & ~0xf);
145     while (!char_avail())
146       ;
147     ch = rd(TRB);
148     wr(IER, old_ier);
149     return ch;
150   }
151
152   int Uart_pxa::char_avail() const
153   {
154     return rd(LSR) & 1; // DATA READY
155   }
156
157   void Uart_pxa::out_char(char c) const
158   {
159     // hmm
160     write(&c, 1);
161   }
162
163   int Uart_pxa::write(char const *s, unsigned long count) const
164   {
165     /* disable uart irqs */
166     char old_ier;
167     unsigned i;
168     old_ier = rd(IER);
169     wr(IER, old_ier & ~0x0f);
170
171     /* transmission */
172     for (i = 0; i < count; i++) {
173       while (!(rd(LSR) & 0x20 /* THRE */))
174         ;
175       if (s[i] == '\346')
176         wr(TRB, '\265');
177       else
178         wr(TRB, s[i]);
179       if (s[i]=='\n') {
180         while (!(rd(LSR) & 0x20 /* THRE */))
181           ;
182         wr(TRB, '\r');
183       }
184     }
185
186     /* wait till everything is transmitted */
187     while (!(rd(LSR) & 0x40 /* TSRE */))
188       ;
189
190     wr(IER, old_ier);
191     return 1;
192   }
193
194 };
195