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