]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/lib/uart/uart_s3c2410.cc
12ba823788cdf28898e011ca93346bf63061dd4a
[l4.git] / kernel / fiasco / src / lib / uart / uart_s3c2410.cc
1 #include "uart_s3c2410.h"
2 #include "poll_timeout_counter.h"
3
4 namespace L4
5 {
6   enum
7   {
8     Type_24xx, Type_64xx, Type_s5pv210,
9   };
10
11   enum
12   {
13     ULCON   = 0x0,  // line control register
14     UCON    = 0x4,  // control register
15     UFCON   = 0x8,  // FIFO control register
16     UMCON   = 0xc,  // modem control register
17     UTRSTAT = 0x10, // Tx/Rx status register
18     UERSTAT = 0x14, // Rx error status register
19     UFSTAT  = 0x18, // FIFO status register
20     UMSTAT  = 0x1c, // modem status register
21     UTXH    = 0x20, // transmit buffer register (little endian, 0x23 for BE)
22     URXH    = 0x24, // receive buffer register (little endian, 0x27 for BE)
23     UBRDIV  = 0x28, // baud rate divisor register
24     // 64xx++
25     UINTP   = 0x30, // interrupt pending register
26     UINTSP  = 0x34, // interrupt source pending register
27     UINTM   = 0x38, // interrupt mask register
28
29
30     ULCON_8N1_MODE = 0x3,
31
32     UCON_MODE_RECEIVE_IRQ_POLL  = 1 << 0,
33     UCON_MODE_TRANSMIT_IRQ_POLL = 1 << 2,
34     UCON_SEND_BREAK_SIGNAL      = 1 << 4,
35     UCON_LOOPBACK_MODE          = 1 << 5,
36     UCON_RX_ERROR_STATUS_IRQ_EN = 1 << 6,
37     UCON_RX_TIME_OUT_EN         = 1 << 7,
38     UCON_MODE =   UCON_MODE_RECEIVE_IRQ_POLL
39                 | UCON_MODE_TRANSMIT_IRQ_POLL
40                 | UCON_RX_TIME_OUT_EN,
41
42     UFCON_ENABLE        = 1 << 0, // enable fifo
43     UFCON_RX_FIFO_RESET = 1 << 1, // Rx Fifo reset
44     UFCON_TX_FIFO_RESET = 1 << 2, // Tx Fifo reset
45
46     UMCON_AFC = 1 << 4,
47
48     UTRSTAT_Rx_RDY = 1 << 0,
49     UTRSTAT_Tx_RDY = 1 << 1,
50
51     UINT_RXD   = 1 << 0,
52     UINT_ERROR = 1 << 1,
53     UINT_TXD   = 1 << 2,
54     UINT_MODEM = 1 << 3,
55
56     // 2410
57     UFSTAT_2410_Rx_COUNT_MASK = 0x00f,
58     UFSTAT_2410_Tx_COUNT_MASK = 0x0f0,
59     UFSTAT_2410_RxFULL        = 0x100,
60     UFSTAT_2410_TxFULL        = 0x200,
61
62     // 64xx
63     UFSTAT_64XX_Rx_COUNT_MASK = 0x003f,
64     UFSTAT_64XX_Tx_COUNT_MASK = 0x3f00,
65     UFSTAT_64XX_RxFULL        = 0x0040,
66     UFSTAT_64XX_TxFULL        = 0x4000,
67
68     // s5pv210
69     UFSTAT_S5PV210_Rx_COUNT_MASK = 0x000000ff,
70     UFSTAT_S5PV210_Tx_COUNT_MASK = 0x00ff0000,
71     UFSTAT_S5PV210_RxFULL        = 0x00000100,
72     UFSTAT_S5PV210_TxFULL        = 0x01000000,
73   };
74
75
76   void Uart_s3c::fifo_reset()
77   {
78     _regs->write<unsigned int>(UFCON, UFCON_RX_FIFO_RESET | UFCON_TX_FIFO_RESET);
79     Poll_timeout_counter i(3000000);
80     while (i.test(_regs->read<unsigned int>(UFCON) & (UFCON_RX_FIFO_RESET | UFCON_TX_FIFO_RESET)))
81       ;
82   }
83
84
85   bool Uart_s3c::startup(Io_register_block const *regs)
86   {
87     _regs = regs;
88
89     fifo_reset();
90 #if 0
91     _regs->write<unsigned int>(UMCON, 0);
92 #endif
93
94     _regs->write<unsigned int>(ULCON, ULCON_8N1_MODE);
95     _regs->write<unsigned int>(UCON,  UCON_MODE);
96     _regs->write<unsigned int>(UFCON, UFCON_ENABLE);
97
98     switch (type())
99       {
100       case Type_24xx:
101         break;
102       case Type_64xx:
103       case Type_s5pv210:
104         _regs->write<unsigned int>(UINTM, ~UINT_RXD); // mask all but receive irq
105         _regs->write<unsigned int>(UINTP, ~0); // clear all pending irqs
106         break;
107       }
108 #if 0
109     _regs->write<unsigned int>(UBRDIV, 0x23);
110 #endif
111
112     return true;
113   }
114
115   void Uart_s3c::shutdown()
116   {
117     // more
118   }
119
120   bool Uart_s3c::change_mode(Transfer_mode, Baud_rate r)
121   {
122     if (r != 115200)
123       return false;
124
125 #if 0
126     _regs->write<unsigned int>(ULCON, ULCON_8N1_MODE);
127     _regs->write<unsigned int>(UCON,  UCON_MODE);
128     _regs->write<unsigned int>(UFCON, 1);
129
130     _regs->write<unsigned int>(UBRDIV, 0x23);
131 #endif
132
133     return true;
134   }
135
136   int Uart_s3c::get_char(bool blocking) const
137   {
138     while (!char_avail())
139       if (!blocking)
140         return -1;
141
142     _regs->read<unsigned int>(UFCON);
143     int c = _regs->read<unsigned int>(URXH) & 0xff;
144     ack_rx_irq();
145     return c;
146   }
147
148   int Uart_s3c::char_avail() const
149   {
150     return is_rx_fifo_non_empty();
151   }
152
153   void Uart_s3c::out_char(char c) const
154   {
155     wait_for_non_full_tx_fifo();
156     _regs->write<unsigned int>(UTXH, c);
157   }
158
159   int Uart_s3c::write(char const *s, unsigned long count) const
160   {
161     unsigned long c = count;
162     while (c--)
163       out_char(*s++);
164     wait_for_empty_tx_fifo();
165
166     return count;
167   }
168
169   // -----------------------
170
171   void Uart_s3c2410::wait_for_empty_tx_fifo() const
172   {
173     Poll_timeout_counter i(3000000);
174     while (i.test(_regs->read<unsigned int>(UFSTAT) & (UFSTAT_2410_Tx_COUNT_MASK | UFSTAT_2410_TxFULL)))
175       ;
176   }
177
178   void Uart_s3c2410::wait_for_non_full_tx_fifo() const
179   {
180     Poll_timeout_counter i(3000000);
181     while (i.test(_regs->read<unsigned int>(UFSTAT) & UFSTAT_2410_TxFULL))
182       ;
183   }
184
185   unsigned Uart_s3c2410::is_rx_fifo_non_empty() const
186   {
187     return _regs->read<unsigned int>(UFSTAT) & (UFSTAT_2410_Rx_COUNT_MASK | UFSTAT_2410_RxFULL);
188   }
189
190   void Uart_s3c2410::auto_flow_control(bool on)
191   {
192     _regs->write<unsigned int>(UMCON, (_regs->read<unsigned int>(UMCON) & ~UMCON_AFC) | (on ? UMCON_AFC : 0));
193   }
194
195   // -----------------------
196
197   void Uart_s3c64xx::wait_for_empty_tx_fifo() const
198   {
199     Poll_timeout_counter i(3000000);
200     while (i.test(_regs->read<unsigned int>(UFSTAT) & (UFSTAT_64XX_Tx_COUNT_MASK | UFSTAT_64XX_TxFULL)))
201       ;
202   }
203
204   void Uart_s3c64xx::wait_for_non_full_tx_fifo() const
205   {
206     Poll_timeout_counter i(3000000);
207     while (i.test(_regs->read<unsigned int>(UFSTAT) & UFSTAT_64XX_TxFULL))
208       ;
209   }
210
211   unsigned Uart_s3c64xx::is_rx_fifo_non_empty() const
212   {
213     return _regs->read<unsigned int>(UFSTAT) & (UFSTAT_64XX_Rx_COUNT_MASK | UFSTAT_64XX_RxFULL);
214   }
215
216   void Uart_s3c64xx::ack_rx_irq() const
217   {
218     _regs->write<unsigned int>(UINTP, UINT_RXD);
219   }
220
221   // -----------------------
222
223   void Uart_s5pv210::wait_for_empty_tx_fifo() const
224   {
225     Poll_timeout_counter i(3000000);
226     while (i.test(_regs->read<unsigned int>(UFSTAT) & (UFSTAT_S5PV210_Tx_COUNT_MASK | UFSTAT_S5PV210_TxFULL)))
227       ;
228   }
229
230   void Uart_s5pv210::wait_for_non_full_tx_fifo() const
231   {
232     Poll_timeout_counter i(3000000);
233     while (i.test(_regs->read<unsigned int>(UFSTAT) & UFSTAT_S5PV210_TxFULL))
234       ;
235   }
236
237   unsigned Uart_s5pv210::is_rx_fifo_non_empty() const
238   {
239     return _regs->read<unsigned int>(UFSTAT) & (UFSTAT_S5PV210_Rx_COUNT_MASK | UFSTAT_S5PV210_RxFULL);
240   }
241
242   void Uart_s5pv210::ack_rx_irq() const
243   {
244     _regs->write<unsigned int>(UINTP, UINT_RXD);
245   }
246 };
247