]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/arm_drivers/drv/src/pxa/uart.c
8357856ff60b49f0ccc3f37096a815629277d962
[l4.git] / l4 / pkg / arm_drivers / drv / src / pxa / uart.c
1 /*
2  * UART Driver PXA
3  */
4
5 #include <l4/arm_drivers_c/uart.h>
6
7 enum {
8   Base_rate     = 921600,
9   Base_ier_bits = 1 << 6,
10 };
11
12 enum {
13   PAR_NONE = 0x00,
14   PAR_EVEN = 0x18,
15   PAR_ODD  = 0x08,
16   DAT_5    = 0x00,
17   DAT_6    = 0x01,
18   DAT_7    = 0x02,
19   DAT_8    = 0x03,
20   STOP_1   = 0x00,
21   STOP_2   = 0x04,
22
23   MODE_8N1 = PAR_NONE | DAT_8 | STOP_1,
24   MODE_7E1 = PAR_EVEN | DAT_7 | STOP_1,
25
26   // these two values are to leave either mode
27   // or baud rate unchanged on a call to change_mode
28   MODE_NC  = 0x1000000,
29   BAUD_NC  = 0x1000000,
30 };
31
32 enum Registers {
33   TRB      = 0, // Transmit/Receive Buffer  (read/write)
34   BRD_LOW  = 0, // Baud Rate Divisor LSB if bit 7 of LCR is set  (read/write)
35   IER      = 1, // Interrupt Enable Register  (read/write)
36   BRD_HIGH = 1, // Baud Rate Divisor MSB if bit 7 of LCR is set  (read/write)
37   IIR      = 2, // Interrupt Identification Register  (read only)
38   FCR      = 2, // 16550 FIFO Control Register  (write only)
39   LCR      = 3, // Line Control Register  (read/write)
40   MCR      = 4, // Modem Control Register  (read/write)
41   LSR      = 5, // Line Status Register  (read only)
42   MSR      = 6, // Modem Status Register  (read only)
43   SPR      = 7, // Scratch Pad Register  (read/write)
44 };
45
46 unsigned port;
47 int _irq;
48
49 static inline
50 void outb(char b, enum Registers reg)
51 {
52   *(volatile char *)((port+reg)*4) = b;
53 }
54
55 static inline
56 char inb(enum Registers reg)
57 {
58   return *(volatile char *)((port+reg)*4);
59 }
60
61
62 static inline
63 void mcr_set(char b)
64 {
65   outb(b, MCR);
66 }
67
68 static inline
69 char mcr_get(void)
70 {
71   return inb(MCR);
72 }
73
74 static inline
75 void fcr_set(char b)
76 {
77   outb(b, FCR);
78 }
79
80 static inline
81 void lcr_set(char b)
82 {
83   outb(b, LCR);
84 }
85
86 static inline
87 char lcr_get(void)
88 {
89   return inb(LCR);
90 }
91
92 static inline
93 void ier_set(char b)
94 {
95   outb(b, IER);
96 }
97
98 static inline
99 char ier_get(void)
100 {
101   return inb(IER);
102 }
103
104 static inline
105 char iir_get(void)
106 {
107   return inb(IIR);
108 }
109
110 static inline
111 char msr_get(void)
112 {
113   return inb(MSR);
114 }
115
116 static inline
117 char lsr_get(void)
118 {
119   return inb(LSR);
120 }
121
122 static inline
123 void trb_set(char b)
124 {
125   outb(b, TRB);
126 }
127
128 static inline
129 char trb_get(void)
130 {
131   return inb(TRB);
132 }
133
134
135
136
137 static int uart_valid(void)
138 {
139   char scratch, scratch2, scratch3;
140
141   scratch = ier_get();
142   ier_set(0x00);
143
144   scratch2 = ier_get();
145   ier_set(0x0f);
146
147   scratch3 = ier_get();
148   ier_set(scratch);
149
150   return (scratch2 == 0x00 && scratch3 == 0x0f);
151 }
152
153
154 int uart_startup(l4_addr_t _port, unsigned __irq)
155 {
156   port = _port;
157   _irq  = __irq;
158
159   if (!uart_valid())
160     return false;
161
162   proc_status o = proc_cli_save();
163   ier_set(Base_ier_bits);/* disable all rs-232 interrupts */
164   mcr_set(0x0b);         /* out2, rts, and dtr enabled */
165   fcr_set(1);            /* enable fifo */
166   fcr_set(0x07);         /* clear rcv xmit fifo */
167   fcr_set(1);            /* enable fifo */
168   lcr_set(0);            /* clear line control register */
169
170   /* clearall interrupts */
171   /*read*/ msr_get(); /* IRQID 0*/
172   /*read*/ iir_get(); /* IRQID 1*/
173   /*read*/ trb_get(); /* IRQID 2*/
174   /*read*/ lsr_get(); /* IRQID 3*/
175
176   while(lsr_get() & 1/*DATA READY*/)
177     /*read*/ trb_get();
178   proc_sti_restore(o);
179   return true;
180 }
181
182 void uart_shutdown(void)
183 {
184   proc_status o = proc_cli_save();
185   mcr_set(0x06);
186   fcr_set(0);
187   lcr_set(0);
188   ier_set(0);
189   proc_sti_restore(o);
190 }
191
192 int uart_change_mode(TransferMode m, BaudRate r)
193 {
194   proc_status o = proc_cli_save();
195   char old_lcr = lcr_get();
196   if(r != BAUD_NC) {
197     l4_uint16_t divisor = Base_rate / r;
198     lcr_set(old_lcr | 0x80/*DLAB*/);
199     trb_set(divisor & 0x0ff );        /* BRD_LOW  */
200     ier_set((divisor >> 8) & 0x0ff ); /* BRD_HIGH */
201     lcr_set(old_lcr);
202   }
203   if (m != MODE_NC)
204     lcr_set(m & 0x07f);
205
206   proc_sti_restore(o);
207   return true;
208 }
209
210 #if 0
211 int uart_getmode(void)
212 {
213   return lcr_get() & 0x7f;
214 }
215 #endif
216
217 int uart_get_mode(enum uart_mode_type type)
218 {
219   switch (type)
220     {
221       case UART_MODE_TYPE_8N1:
222         return MODE_8N1;
223       case UART_MODE_TYPE_NONE:
224         return 0;
225     }
226   return 0;
227 }
228
229 int uart_write(char const *s, unsigned count)
230 {
231   /* disable uart irqs */
232   char old_ier;
233   unsigned i;
234   old_ier = ier_get();
235   ier_set(old_ier & ~0x0f);
236
237   /* transmission */
238   for (i = 0; i < count; i++) {
239     while (!(lsr_get() & 0x20 /* THRE */))
240       ;
241     if (s[i] == '\346')
242       trb_set('\265');
243     else
244       trb_set(s[i]);
245     if (s[i]=='\n') {
246       while (!(lsr_get() & 0x20 /* THRE */))
247         ;
248       trb_set('\r');
249     }
250   }
251
252   /* wait till everything is transmitted */
253   while (!(lsr_get() & 0x40 /* TSRE */))
254     ;
255
256   ier_set(old_ier);
257   return 1;
258 }
259
260 int uart_getchar(int blocking)
261 {
262   char old_ier, ch;
263
264   if (!blocking && !(lsr_get() & 1 /* DATA READY */))
265     return -1;
266
267   old_ier = ier_get();
268   ier_set(old_ier & ~0x0f);
269   while(!(lsr_get() & 1 /* DATA READY */))
270     ;
271   ch = trb_get();
272   ier_set(old_ier);
273   return ch;
274 }
275
276 int uart_char_avail(void)
277 {
278   if (lsr_get() & 1 /* DATA READY */)
279     return 1;
280
281   return 0;
282 }
283
284 l4_addr_t uart_base(void)
285 {
286   return 0x40100000 / 4;
287 }