xref: /plan9/sys/src/9/ppc/uartsaturn.c (revision 458db83292ea45506704800dedf36a95598fc2ec)
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 #include "msaturn.h"
9 
10 enum{
11 	UartAoffs = Saturn + 0x0a00,
12 	UartBoffs = Saturn + 0x0b00,
13 	Nuart = 2,
14 
15 	Baudfreq = 14745600 / 16,
16 	Lcr_div = RBIT(1, uchar),
17 	Lcr_peven = RBIT(3, uchar),
18 	Lcr_pen = RBIT(4, uchar),
19 	Lcr_stop = RBIT(5, uchar),
20 	Lcr_wrdlenmask = RBIT(6, uchar) | RBIT(7, uchar),
21 	Lcr_wrdlenshift = 0,
22 	Lsr_tbre = RBIT(2, uchar),
23 	Fcr_txreset = RBIT(5, uchar),
24 	Fcr_rxreset = RBIT(6, uchar),
25 	Iir_txempty = RBIT(5, uchar),
26 	Iir_rxfull = RBIT(6, uchar),
27 	Iir_rxerr = RBIT(7, uchar),
28 	Ier_rxerr = RBIT(5, uchar),
29 	Ier_txempty = RBIT(6, uchar),
30 	Ier_rxfull = RBIT(7, uchar),
31 	Lsr_rxavail = RBIT(7, uchar),
32 	Txsize = 16,
33 	Rxsize = 16,
34 };
35 
36 typedef struct Saturnuart Saturnuart;
37 struct Saturnuart {
38 	uchar	rxb;
39 #define txb	rxb
40 #define dll	rxb
41 	uchar	ier;			// Interrupt enable, divisor latch
42 #define dlm	ier
43 	uchar	iir;			// Interrupt identification, fifo control
44 #define fcr	iir
45 	uchar	lcr;			// Line control register
46 	uchar	f1;
47 	uchar	lsr;			// Line status register
48 	ushort	f2;
49 };
50 
51 typedef struct UartData UartData;
52 struct UartData {
53 	int			suno;	/* saturn uart number: 0 or 1 */
54 	Saturnuart	*su;
55 	char			*rxbuf;
56 	char			*txbuf;
57 	int			initialized;
58 	int			enabled;
59 } uartdata[Nuart];
60 
61 extern PhysUart saturnphysuart;
62 
63 Uart suart[Nuart] = {
64 	{
65 		.name = "SaturnUart1",
66 		.baud = 19200,
67 		.bits = 8,
68 		.stop = 1,
69 		.parity = 'n',
70 		.phys = &saturnphysuart,
71 		.special = 0,
72 	},
73 	{
74 		.name = "SaturnUart2",
75 		.baud = 115200,
76 		.bits = 8,
77 		.stop = 1,
78 		.parity = 'n',
79 		.phys = &saturnphysuart,
80 		.special = 0,
81 	},
82 };
83 
84 static void suinterrupt(Ureg*, void*);
85 
86 static Uart*
supnp(void)87 supnp(void)
88 {
89 	int i;
90 
91 	for (i = 0; i < nelem(suart)-1; i++)
92 		suart[i].next = &suart[i + 1];
93 	suart[nelem(suart)-1].next=nil;
94 	return suart;
95 }
96 
97 static void
suinit(Uart * uart)98 suinit(Uart*uart)
99 {
100 	UartData *ud;
101 	Saturnuart *su;
102 
103 	ud = uart->regs;
104 	su = ud->su;
105 	su->fcr=Fcr_txreset|Fcr_rxreset;
106 	ud->initialized=1;
107 }
108 
109 static void
suenable(Uart * uart,int ie)110 suenable(Uart*uart, int ie)
111 {
112 	Saturnuart *su;
113 	UartData *ud;
114 	int nr;
115 
116 	nr = uart - suart;
117 	if (nr < 0 || nr > Nuart)
118 		panic("No uart %d", nr);
119 	ud = uartdata + nr;
120 	ud->suno = nr;
121 	su=ud->su = (Saturnuart*)((nr == 0)? UartAoffs: UartBoffs);
122 	uart->regs = ud;
123 
124 	if(ud->initialized==0)
125 		suinit(uart);
126 
127 	if(!ud->enabled && ie){
128 		intrenable(Vecuart0+nr , suinterrupt, uart, uart->name);
129 		su->ier=Ier_txempty|Ier_rxfull;
130 		ud->enabled=1;
131 	}
132 }
133 
134 
135 static long
sustatus(Uart * uart,void * buf,long n,long offset)136 sustatus(Uart* uart, void* buf, long n, long offset)
137 {
138 	Saturnuart *su;
139 	char p[128];
140 
141 	su = ((UartData*)uart->regs)->su;
142 	snprint(p, sizeof p, "b%d c%d e%d l%d m0 p%c s%d i1\n"
143 		"dev(%d) type(%d) framing(%d) overruns(%d)\n",
144 
145 		uart->baud,
146 		uart->hup_dcd,
147 		uart->hup_dsr,
148 		Txsize,
149 		(su->lcr & Lcr_pen)? ((su->lcr & Lcr_peven) ? 'e': 'o'): 'n',
150 		(su->lcr & Lcr_stop)? 2: 1,
151 
152 		uart->dev,
153 		uart->type,
154 		uart->ferr,
155 		uart->oerr);
156 	n = readstr(offset, buf, n, p);
157 	free(p);
158 
159 	return n;
160 }
161 
162 static void
sufifo(Uart *,int)163 sufifo(Uart*, int)
164 {}
165 
166 static void
sudtr(Uart *,int)167 sudtr(Uart*, int)
168 {}
169 
170 static void
surts(Uart *,int)171 surts(Uart*, int)
172 {}
173 
174 static void
sumodemctl(Uart *,int)175 sumodemctl(Uart*, int)
176 {}
177 
178 static int
suparity(Uart * uart,int parity)179 suparity(Uart*uart, int parity)
180 {
181 	int lcr;
182 	Saturnuart *su;
183 
184 	su = ((UartData*)uart->regs)->su;
185 
186 	lcr = su->lcr & ~(Lcr_pen|Lcr_peven);
187 
188 	switch(parity){
189 	case 'e':
190 		lcr |= (Lcr_pen|Lcr_peven);
191 		break;
192 	case 'o':
193 		lcr |= Lcr_pen;
194 		break;
195 	case 'n':
196 	default:
197 		break;
198 	}
199 
200 	su->lcr = lcr;
201 	uart->parity = parity;
202 
203 	return 0;
204 }
205 
206 static int
sustop(Uart * uart,int stop)207 sustop(Uart* uart, int stop)
208 {
209 	int lcr;
210 	Saturnuart *su;
211 
212 	su = ((UartData*)uart->regs)->su;
213 	lcr = su->lcr & ~Lcr_stop;
214 
215 	switch(stop){
216 	case 1:
217 		break;
218 	case 2:
219 		lcr |= Lcr_stop;
220 		break;
221 	default:
222 		return -1;
223 	}
224 
225 	/* Set new value and reenable if device was previously enabled */
226 	su->lcr = lcr;
227 	uart->stop = stop;
228 
229 	return 0;
230 }
231 
232 static int
subits(Uart * uart,int n)233 subits(Uart*uart, int n)
234 {
235 	Saturnuart *su;
236 	uchar lcr;
237 
238 	su = ((UartData*)uart->regs)->su;
239 	if(n<5||n>8)
240 		return -1;
241 
242 	lcr = su->lcr & ~Lcr_wrdlenmask;
243 	lcr |= (n-5) << Lcr_wrdlenshift;
244 	su->lcr = lcr;
245 	return 0;
246 }
247 
248 static int
subaud(Uart * uart,int baud)249 subaud(Uart* uart, int baud)
250 {
251 	ushort v;
252 	Saturnuart *su;
253 
254 	if (uart->enabled){
255 		su = ((UartData*)uart->regs)->su;
256 
257 		if(baud <= 0)
258 			return -1;
259 
260 		v = Baudfreq / baud;
261 		su->lcr |= Lcr_div;
262 		su->dll = v;
263 		su->dlm = v >> 8;
264 		su->lcr &= ~Lcr_div;
265 	}
266 	uart->baud = baud;
267 
268 	return 0;
269 }
270 
271 static void
subreak(Uart *,int)272 subreak(Uart*, int)
273 {}
274 
275 static void
sukick(Uart * uart)276 sukick(Uart *uart)
277 {
278 	Saturnuart *su;
279 	int i;
280 
281 	if(uart->blocked)
282 		return;
283 
284 	su = ((UartData*)uart->regs)->su;
285 	if((su->iir & Iir_txempty) == 0)
286 		return;
287 
288 	for(i = 0; i < Txsize; i++){
289 		if(uart->op >= uart->oe && uartstageoutput(uart) == 0)
290 			break;
291 		su->txb = *(uart->op++);
292 		su->ier |= Ier_txempty;
293 		break;
294 	}
295 }
296 
297 static void
suputc(Uart * uart,int c)298 suputc(Uart *uart, int c)
299 {
300 	Saturnuart *su;
301 
302 	su = ((UartData*)uart->regs)->su;
303 	while((su->lsr&Lsr_tbre) == 0)
304 		;
305 
306 	su->txb=c;
307 	while((su->lsr&Lsr_tbre) == 0)
308 			;
309 }
310 
311 static int
getchars(Uart * uart,uchar * cbuf)312 getchars(Uart *uart, uchar *cbuf)
313 {
314 	int nc;
315 	UartData *ud;
316 	Saturnuart *su;
317 
318 	ud = uart->regs;
319 	su = ud->su;
320 
321 	while((su->lsr&Lsr_rxavail) == 0)
322 		;
323 
324 	*cbuf++ = su->rxb;
325 	nc = 1;
326 	while(su->lsr&Lsr_rxavail){
327 		*cbuf++ = su->rxb;
328 		nc++;
329 	}
330 	return nc;
331 }
332 
333 static int
sugetc(Uart * uart)334 sugetc(Uart *uart)
335 {
336 	static uchar buf[128], *p;
337 	static int cnt;
338 	char	c;
339 
340 	if (cnt <= 0) {
341 		cnt = getchars(uart, buf);
342 		p = buf;
343 	}
344 	c = *p++;
345 	cnt--;
346 	return c;
347 }
348 
349 static void
suinterrupt(Ureg *,void * u)350 suinterrupt(Ureg*, void*u)
351 {
352 	Saturnuart *su;
353 	Uart *uart;
354 	uchar iir;
355 
356 	uart = u;
357 	if (uart == nil)
358 		panic("uart is nil");
359 	su = ((UartData*)uart->regs)->su;
360 	iir = su->iir;
361 	if(iir&Iir_rxfull)
362 		while(su->lsr&Lsr_rxavail)
363 			uartrecv(uart, su->rxb);
364 	if(iir & Iir_txempty){
365 		su->ier&=~Ier_txempty;
366 		uartkick(uart);
367 	}
368 	if (iir & Iir_rxerr)
369 		uart->oerr++;
370 	intack();
371 }
372 
373 static void
sudisable(Uart * uart)374 sudisable(Uart* uart)
375 {
376 	Saturnuart *su;
377 
378 	su = ((UartData*)uart->regs)->su;
379 	su->ier&=~(Ier_txempty|Ier_rxfull);
380 }
381 
382 PhysUart saturnphysuart = {
383 	.name		= "su",
384 	.pnp			= supnp,
385 	.enable		= suenable,
386 	.disable		= sudisable,
387 	.kick			= sukick,
388 	.dobreak		= subreak,
389 	.baud		= subaud,
390 	.bits			= subits,
391 	.stop			= sustop,
392 	.parity		= suparity,
393 	.modemctl	= sumodemctl,
394 	.rts			= surts,
395 	.dtr			= sudtr,
396 	.status		= sustatus,
397 	.fifo			= sufifo,
398 	.getc			= sugetc,
399 	.putc			= suputc,
400 };
401 
402 void
console(void)403 console(void)
404 {
405 	Uart *uart;
406 	int n;
407 	char *cmd, *p;
408 
409 	if((p = getconf("console")) == nil)
410 		return;
411 	n = strtoul(p, &cmd, 0);
412 	if(p == cmd)
413 		return;
414 	if(n < 0 || n >= nelem(suart))
415 		return;
416 
417 	uart = suart + n;
418 
419 /*	uartctl(uart, "b115200 l8 pn s1"); */
420 	if(*cmd != '\0')
421 		uartctl(uart, cmd);
422 	(*uart->phys->enable)(uart, 0);
423 
424 	consuart = uart;
425 	uart->console = 1;
426 }
427 
428 Saturnuart*uart = (Saturnuart*)UartAoffs;
429 
430 void
dbgputc(int c)431 dbgputc(int c)
432 {
433 	while((uart->lsr&Lsr_tbre) == 0)
434 		;
435 
436 	uart->txb=c;
437 	while((uart->lsr&Lsr_tbre) == 0)
438 			;
439 }
440 
441 void
dbgputs(char * s)442 dbgputs(char*s)
443 {
444 	while(*s)
445 		dbgputc(*s++);
446 }
447 
448 void
dbgputx(ulong x)449 dbgputx(ulong x)
450 {
451 	int i;
452 	char c;
453 
454 	for(i=0; i < sizeof(ulong) * 2; i++){
455 		c = ((x >> (28 - i * 4))) & 0xf;
456 		if(c >= 0 && c <= 9)
457 			c += '0';
458 		else
459 			c += 'a' - 10;
460 
461 		while((uart->lsr&Lsr_tbre) == 0)
462 			;
463 
464 		uart->txb=c;
465 	}
466 	while((uart->lsr&Lsr_tbre) == 0)
467 			;
468 
469 	uart->txb='\n';
470 	while((uart->lsr&Lsr_tbre) == 0)
471 			;
472 }
473