]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/bitsy/uartsa1110.c
merge
[plan9front.git] / sys / src / 9 / bitsy / uartsa1110.c
1 #include        "u.h"
2 #include        "../port/lib.h"
3 #include        "mem.h"
4 #include        "dat.h"
5 #include        "fns.h"
6 #include        "io.h"
7 #include        "../port/error.h"
8
9 #include        "../port/netif.h"
10
11 /* this isn't strictly an sa1110 driver.  The rts/cts stuff is h3650 specific */
12
13 static void sa1110_uartpower(Uart *, int);
14
15 enum
16 {
17         /* ctl[0] bits */
18         Parity=         1<<0,
19         Even=           1<<1,
20         Stop2=          1<<2,
21         Bits8=          1<<3,
22         SCE=            1<<4,   /* synchronous clock enable */
23         RCE=            1<<5,   /* rx on falling edge of clock */
24         TCE=            1<<6,   /* tx on falling edge of clock */
25
26         /* ctl[3] bits */
27         Rena=           1<<0,   /* receiver enable */
28         Tena=           1<<1,   /* transmitter enable */
29         Break=          1<<2,   /* force TXD3 low */
30         Rintena=        1<<3,   /* enable receive interrupt */
31         Tintena=        1<<4,   /* enable transmitter interrupt */
32         Loopback=       1<<5,   /* loop back data */
33
34         /* data bits */
35         DEparity=       1<<8,   /* parity error */
36         DEframe=        1<<9,   /* framing error */
37         DEoverrun=      1<<10,  /* overrun error */
38
39         /* status[0] bits */
40         Tint=           1<<0,   /* transmit fifo half full interrupt */
41         Rint0=          1<<1,   /* receiver fifo 1/3-2/3 full */
42         Rint1=          1<<2,   /* receiver fifo not empty and receiver idle */
43         Breakstart=     1<<3,
44         Breakend=       1<<4,
45         Fifoerror=      1<<5,   /* fifo error */
46
47         /* status[1] bits */
48         Tbusy=          1<<0,   /* transmitting */
49         Rnotempty=      1<<1,   /* receive fifo not empty */
50         Tnotfull=       1<<2,   /* transmit fifo not full */
51         ParityError=    1<<3,
52         FrameError=     1<<4,
53         Overrun=        1<<5,
54 };
55
56 extern PhysUart sa1110physuart;
57
58 //static
59 Uart sa1110uart[2] = {
60 {       .regs           = (void*)UART3REGS,
61         .name           = "serialport3",
62         .freq           = ClockFreq,
63         .bits           = 8,
64         .stop           = 1,
65         .parity         = 'n',
66         .baud           = 115200,
67         .phys           = &sa1110physuart,
68         .special        = 0,
69         .next           = &sa1110uart[1], },
70
71 {       .regs           = (void*)UART1REGS,
72         .name           = "serialport1",
73         .freq           = ClockFreq,
74         .bits           = 8,
75         .stop           = 1,
76         .parity         = 'n',
77         .baud           = 115200,
78         .phys           = &sa1110physuart,
79         .putc           = µcputc,
80         .special        = 0,
81         .next           = nil, },
82 };
83 static Uart* µcuart;
84
85 #define R(p) ((Uartregs*)((p)->regs))
86 #define SR(p) ((Uartregs*)((p)->saveregs))
87
88 /*
89  *  enable a port's interrupts.  set DTR and RTS
90  */
91 static void
92 sa1110_uartenable(Uart *p, int intena)
93 {
94         ulong s;
95
96         s = R(p)->ctl[3] & ~(Rintena|Tintena|Rena|Tena);
97         if(intena)
98                 R(p)->ctl[3] = s |Rintena|Tintena|Rena|Tena;
99         else
100                 R(p)->ctl[3] = s | Rena|Tena;
101 }
102
103 /*
104  *  disable interrupts. clear DTR, and RTS
105  */
106 static void
107 sa1110_uartdisable(Uart *p)
108 {
109         R(p)->ctl[3] &= ~(Rintena|Tintena|Rena|Tena);
110 }
111
112 static long
113 sa1110_uartstatus(Uart *p, void *buf, long n, long offset)
114 {
115         char str[256];
116         ulong ctl0;
117
118         ctl0 = R(p)->ctl[0];
119         snprint(str, sizeof(str),
120                 "b%d c%d d%d e%d l%d m%d p%c r%d s%d i%d\n"
121                 "dev(%d) type(%d) framing(%d) overruns(%d)%s%s%s%s\n",
122
123                 p->baud,
124                 p->hup_dcd, 
125                 0,
126                 p->hup_dsr,
127                 (ctl0 & Bits8) ? 8 : 7,
128                 0, 
129                 (ctl0 & Parity) ? ((ctl0 & Even) ? 'e' : 'o') : 'n',
130                 0,
131                 (ctl0 & Stop2) ? 2 : 1,
132                 1,
133
134                 p->dev,
135                 p->type,
136                 p->ferr,
137                 p->oerr, 
138                 "",
139                 "",
140                 "",
141                 "" );
142         return readstr(offset, buf, n, str);
143 }
144
145 /*
146  *  set the buad rate
147  */
148 static int
149 sa1110_uartbaud(Uart *p, int rate)
150 {
151         ulong brconst;
152         ulong ctl3;
153
154         if(rate <= 0)
155                 return -1;
156
157         /* disable */
158         ctl3 = R(p)->ctl[3];
159         R(p)->ctl[3] = 0;
160
161         brconst = p->freq/(16*rate) - 1;
162         R(p)->ctl[1] = (brconst>>8) & 0xf;
163         R(p)->ctl[2] = brconst & 0xff;
164
165         /* reenable */
166         R(p)->ctl[3] = ctl3;
167
168         p->baud = rate;
169         return 0;
170 }
171
172 /*
173  *  send a break
174  */
175 static void
176 sa1110_uartbreak(Uart *p, int ms)
177 {
178         if(ms == 0)
179                 ms = 200;
180
181         R(p)->ctl[3] |= Break;
182         tsleep(&up->sleep, return0, 0, ms);
183         R(p)->ctl[3] &= ~Break;
184 }
185
186 /*
187  *  set bits/char
188  */
189 static int
190 sa1110_uartbits(Uart *p, int n)
191 {
192         ulong ctl0, ctl3;
193
194         ctl0 = R(p)->ctl[0];
195         switch(n){
196         case 7:
197                 ctl0 &= ~Bits8;
198                 break;
199         case 8:
200                 ctl0 |= Bits8;
201                 break;
202         default:
203                 return -1;
204         }
205
206         /* disable */
207         ctl3 = R(p)->ctl[3];
208         R(p)->ctl[3] = 0;
209
210         R(p)->ctl[0] = ctl0;
211
212         /* reenable */
213         R(p)->ctl[3] = ctl3;
214
215         p->bits = n;
216         return 0;
217 }
218
219 /*
220  *  set stop bits
221  */
222 static int
223 sa1110_uartstop(Uart *p, int n)
224 {
225         ulong ctl0, ctl3;
226
227         ctl0 = R(p)->ctl[0];
228         switch(n){
229         case 1:
230                 ctl0 &= ~Stop2;
231                 break;
232         case 2:
233                 ctl0 |= Stop2;
234                 break;
235         default:
236                 return -1;
237         }
238
239         /* disable */
240         ctl3 = R(p)->ctl[3];
241         R(p)->ctl[3] = 0;
242
243         R(p)->ctl[0] = ctl0;
244
245         /* reenable */
246         R(p)->ctl[3] = ctl3;
247
248         p->stop = n;
249         return 0;
250 }
251
252 /*
253  *  turn on/off rts
254  */
255 static void
256 sa1110_uartrts(Uart*, int)
257 {
258 }
259
260 /*
261  *  turn on/off dtr
262  */
263 static void
264 sa1110_uartdtr(Uart*, int)
265 {
266 }
267
268 /*
269  *  turn on/off modem flow control on/off (rts/cts)
270  */
271 static void
272 sa1110_uartmodemctl(Uart *p, int on)
273 {
274         if(on) {
275         } else {
276                 p->cts = 1;
277         }
278 }
279
280 /*
281  *  set parity
282  */
283 static int
284 sa1110_uartparity(Uart *p, int type)
285 {
286         ulong ctl0, ctl3;
287
288         ctl0 = R(p)->ctl[0];
289         switch(type){
290         case 'e':
291                 ctl0 |= Parity|Even;
292                 break;
293         case 'o':
294                 ctl0 |= Parity;
295                 break;
296         default:
297                 ctl0 &= ~(Parity|Even);
298                 break;
299         }
300
301         /* disable */
302         ctl3 = R(p)->ctl[3];
303         R(p)->ctl[3] = 0;
304
305         R(p)->ctl[0] = ctl0;
306
307         /* reenable */
308         R(p)->ctl[3] = ctl3;
309
310         return 0;
311 }
312
313 /*
314  *  restart output if not blocked and OK to send
315  */
316 static void
317 sa1110_uartkick(Uart *p)
318 {
319         int i;
320
321         R(p)->ctl[3] &= ~Tintena;
322
323         if(p->cts == 0 || p->blocked)
324                 return;
325
326         for(i = 0; i < 1024; i++){
327                 if(!(R(p)->status[1] & Tnotfull)){
328                         R(p)->ctl[3] |= Tintena;
329                         break;
330                 }
331                 if(p->op >= p->oe && uartstageoutput(p) == 0)
332                         break;
333                 R(p)->data = *p->op++;
334         }
335 }
336
337 /*
338  *  take an interrupt
339  */
340 static void
341 sa1110_uartintr(Ureg*, void *x)
342 {
343         Uart *p;
344         ulong s;
345         Uartregs *regs;
346
347         p = x;
348         regs = p->regs;
349
350         /* receiver interrupt, snarf bytes */
351         while(regs->status[1] & Rnotempty)
352                 uartrecv(p, regs->data);
353
354         /* remember and reset interrupt causes */
355         s = regs->status[0];
356         regs->status[0] |= s;
357
358         if(s & Tint){
359                 /* transmitter interrupt, restart */
360                 uartkick(p);
361         }
362
363         if(s & (ParityError|FrameError|Overrun)){
364                 if(s & ParityError)
365                         p->parity++;
366                 if(s & FrameError)
367                         p->ferr++;
368                 if(s & Overrun)
369                         p->oerr++;
370         }
371
372         /* receiver interrupt, snarf bytes */
373         while(regs->status[1] & Rnotempty)
374                 uartrecv(p, regs->data);
375 }
376
377 static Uart*
378 sa1110_pnp(void)
379 {
380         return sa1110uart;
381 }
382
383 static int
384 sa1110_getc(Uart *uart)
385 {
386         Uartregs *ur;
387
388         ur = uart->regs;
389         while((ur->status[1] & Rnotempty) == 0)
390                 ;
391         return ur->data;
392 }
393
394 static void
395 sa1110_putc(Uart *uart, int c)
396 {
397         Uartregs *ur;
398
399         ur = uart->regs;
400         /* wait for output ready */
401         while((ur->status[1] & Tnotfull) == 0)
402                 ;
403         ur->data = c;
404         while((ur->status[1] & Tbusy))
405                 ;
406 }
407
408 PhysUart sa1110physuart = {
409         .name=          "sa1110",
410         .pnp=           sa1110_pnp,
411         .enable=        sa1110_uartenable,
412         .disable=       sa1110_uartdisable,
413         .bits=          sa1110_uartbits,
414         .kick=          sa1110_uartkick,
415         .modemctl=      sa1110_uartmodemctl,
416         .baud=          sa1110_uartbaud,
417         .stop=          sa1110_uartstop,
418         .parity=        sa1110_uartparity,
419         .dobreak=       sa1110_uartbreak,
420         .rts=           sa1110_uartrts,
421         .dtr=           sa1110_uartdtr,
422         .status=        sa1110_uartstatus,
423         .power=         sa1110_uartpower,
424         .getc=          sa1110_getc,
425         .putc=          sa1110_putc,
426 };
427
428 /*
429  *  for iprint, just write it
430  */
431 void
432 serialµcputs(uchar *str, int n)
433 {
434         Uartregs *ur;
435
436         if(µcuart == nil)
437                 return;
438         ur = µcuart->regs;
439         while(n-- > 0){
440                 /* wait for output ready */
441                 while((ur->status[1] & Tnotfull) == 0)
442                         ;
443                 ur->data = *str++;
444         }
445         while((ur->status[1] & Tbusy))
446                 ;
447 }
448
449 enum
450 {
451         /* gpclk register 0 */
452         Gpclk_sus=      1<<0,   /* set uart mode */
453 };
454
455 Gpclkregs *gpclkregs;
456
457 /*
458  *  setup all uarts (called early by main() to allow debugging output to
459  *  a serial port)
460  */
461 void
462 sa1110_uartsetup(int console)
463 {
464         Uart *p;
465
466         /* external serial port (eia0) */
467         p = &sa1110uart[0];
468         p->regs = mapspecial(UART3REGS, sizeof(Uartregs));
469         p->saveregs = xalloc(sizeof(Uartregs));
470         /* set eia0 up as a console */
471         if(console){
472                 uartctl(p, "b115200 l8 pn s1");
473                 (*p->phys->enable)(p, 0);
474                 p->console = 1;
475                 consuart = p;
476         }
477         intrenable(IRQ, IRQuart3, sa1110_uartintr, p, p->name);
478
479         /* port for talking to microcontroller (eia1) */
480         gpclkregs = mapspecial(GPCLKREGS, sizeof(Gpclkregs));
481         gpclkregs->r0 = Gpclk_sus;      /* set uart mode */
482
483         p = &sa1110uart[1];
484         p->regs = mapspecial(UART1REGS, sizeof(Uartregs));
485         p->saveregs = xalloc(sizeof(Uartregs));
486         uartctl(p, "b115200 l8 pn s1");
487         µcuart = p;
488         p->special = 1;
489         (*p->phys->enable)(p, 0);
490         intrenable(IRQ, IRQuart1b, sa1110_uartintr, p, p->name);
491 }
492
493 static  void
494 uartcpy(Uartregs *to, Uartregs *from)
495 {
496         to->ctl[0] = from->ctl[0];
497 //      to->ctl[1] = from->ctl[1];
498 //      to->ctl[2] = from->ctl[2];
499         to->ctl[3] = from->ctl[3];
500
501 }
502
503 static void
504 sa1110_uartpower(Uart *p, int powerup)
505 {
506         if (powerup) {
507                 /* power up, restore the registers */
508                 uartcpy(R(p), SR(p));
509                 R(p)->status[0] = R(p)->status[0];
510         } else {
511                 /* power down, save the registers */
512                 uartcpy(SR(p), R(p));
513         }
514 }