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