Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/*
2
 * bcm2835 mini uart (UART1)
3
 */
4
 
5
#include "u.h"
6
#include "../port/lib.h"
7
#include "../port/error.h"
8
#include "mem.h"
9
#include "dat.h"
10
#include "fns.h"
11
#include "io.h"
12
 
13
#define GPIOREGS	(VIRTIO+0x200000)
14
#define AUXREGS		(VIRTIO+0x215000)
15
#define	OkLed		16
16
#define	TxPin		14
17
#define	RxPin		15
18
 
19
/* GPIO regs */
20
enum {
21
	Fsel0	= 0x00>>2,
22
		FuncMask= 0x7,
23
		Input	= 0x0,
24
		Output	= 0x1,
25
		Alt0	= 0x4,
26
		Alt1	= 0x5,
27
		Alt2	= 0x6,
28
		Alt3	= 0x7,
29
		Alt4	= 0x3,
30
		Alt5	= 0x2,
31
	Set0	= 0x1c>>2,
32
	Clr0	= 0x28>>2,
33
	Lev0	= 0x34>>2,
34
	PUD	= 0x94>>2,
35
		Off	= 0x0,
36
		Pulldown= 0x1,
37
		Pullup	= 0x2,
38
	PUDclk0	= 0x98>>2,
39
	PUDclk1	= 0x9c>>2,
40
};
41
 
42
/* AUX regs */
43
enum {
44
	Irq	= 0x00>>2,
45
		UartIrq	= 1<<0,
46
	Enables	= 0x04>>2,
47
		UartEn	= 1<<0,
48
	MuIo	= 0x40>>2,
49
	MuIer	= 0x44>>2,
50
		RxIen	= 1<<0,
51
		TxIen	= 1<<1,
52
	MuIir	= 0x48>>2,
53
	MuLcr	= 0x4c>>2,
54
		Bitsmask= 3<<0,
55
		Bits7	= 2<<0,
56
		Bits8	= 3<<0,
57
	MuMcr	= 0x50>>2,
58
		RtsN	= 1<<1,
59
	MuLsr	= 0x54>>2,
60
		TxDone	= 1<<6,
61
		TxRdy	= 1<<5,
62
		RxRdy	= 1<<0,
63
	MuCntl	= 0x60>>2,
64
		CtsFlow	= 1<<3,
65
		TxEn	= 1<<1,
66
		RxEn	= 1<<0,
67
	MuBaud	= 0x68>>2,
68
};
69
 
70
extern PhysUart miniphysuart;
71
 
72
static Uart miniuart = {
73
	.regs	= (u32int*)AUXREGS,
74
	.name	= "uart0",
75
	.freq	= 250000000,
76
	.phys	= &miniphysuart,
77
};
78
 
79
void
80
gpiosel(uint pin, int func)
81
{	
82
	u32int *gp, *fsel;
83
	int off;
84
 
85
	gp = (u32int*)GPIOREGS;
86
	fsel = &gp[Fsel0 + pin/10];
87
	off = (pin % 10) * 3;
88
	*fsel = (*fsel & ~(FuncMask<<off)) | func<<off;
89
}
90
 
91
void
92
gpiopulloff(uint pin)
93
{
94
	u32int *gp, *reg;
95
	u32int mask;
96
 
97
	gp = (u32int*)GPIOREGS;
98
	reg = &gp[PUDclk0 + pin/32];
99
	mask = 1 << (pin % 32);
100
	gp[PUD] = Off;
101
	microdelay(1);
102
	*reg = mask;
103
	microdelay(1);
104
	*reg = 0;
105
}
106
 
107
void
108
gpioout(uint pin, int set)
109
{
110
	u32int *gp;
111
	int v;
112
 
113
	gp = (u32int*)GPIOREGS;
114
	v = set? Set0 : Clr0;
115
	gp[v + pin/32] = 1 << (pin % 32);
116
}
117
 
118
int
119
gpioin(uint pin)
120
{
121
	u32int *gp;
122
 
123
	gp = (u32int*)GPIOREGS;
124
	return (gp[Lev0 + pin/32] & (1 << (pin % 32))) != 0;
125
}
126
 
127
static void
128
interrupt(Ureg*, void *arg)
129
{
130
	Uart *uart;
131
	u32int *ap;
132
 
133
	uart = arg;
134
	ap = (u32int*)uart->regs;
135
 
136
	coherence();
137
	if(0 && (ap[Irq] & UartIrq) == 0)
138
		return;
139
	if(ap[MuLsr] & TxRdy)
140
		uartkick(uart);
141
	if(ap[MuLsr] & RxRdy){
142
		if(uart->console){
143
			if(uart->opens == 1)
144
				uart->putc = kbdcr2nl;
145
			else
146
				uart->putc = nil;
147
		}
148
		do{
149
			uartrecv(uart, ap[MuIo] & 0xFF);
150
		}while(ap[MuLsr] & RxRdy);
151
	}
152
	coherence();
153
}
154
 
155
static Uart*
156
pnp(void)
157
{
158
	Uart *uart;
159
 
160
	uart = &miniuart;
161
	if(uart->console == 0)
162
		kbdq = qopen(8*1024, 0, nil, nil);
163
	return uart;
164
}
165
 
166
static void
167
enable(Uart *uart, int ie)
168
{
169
	u32int *ap;
170
 
171
	ap = (u32int*)uart->regs;
172
	delay(10);
173
	gpiosel(TxPin, Alt5);
174
	gpiosel(RxPin, Alt5);
175
	gpiopulloff(TxPin);
176
	gpiopulloff(RxPin);
177
	ap[Enables] |= UartEn;
178
	ap[MuIir] = 6;
179
	ap[MuLcr] = Bits8;
180
	ap[MuCntl] = TxEn|RxEn;
181
	ap[MuBaud] = 250000000/(115200*8) - 1;
182
	if(ie){
183
		intrenable(IRQaux, interrupt, uart, 0, "uart");
184
		ap[MuIer] = RxIen|TxIen;
185
	}else
186
		ap[MuIer] = 0;
187
}
188
 
189
static void
190
disable(Uart *uart)
191
{
192
	u32int *ap;
193
 
194
	ap = (u32int*)uart->regs;
195
	ap[MuCntl] = 0;
196
	ap[MuIer] = 0;
197
}
198
 
199
static void
200
kick(Uart *uart)
201
{
202
	u32int *ap;
203
 
204
	ap = (u32int*)uart->regs;
205
	if(uart->blocked)
206
		return;
207
	coherence();
208
	while(ap[MuLsr] & TxRdy){
209
		if(uart->op >= uart->oe && uartstageoutput(uart) == 0)
210
			break;
211
		ap[MuIo] = *(uart->op++);
212
	}
213
	if(ap[MuLsr] & TxDone)
214
		ap[MuIer] &= ~TxIen;
215
	else
216
		ap[MuIer] |= TxIen;
217
	coherence();
218
}
219
 
220
/* TODO */
221
static void
222
dobreak(Uart *uart, int ms)
223
{
224
	USED(uart, ms);
225
}
226
 
227
static int
228
baud(Uart *uart, int n)
229
{
230
	u32int *ap;
231
 
232
	ap = (u32int*)uart->regs;
233
	if(uart->freq == 0 || n <= 0)
234
		return -1;
235
	ap[MuBaud] = (uart->freq + 4*n - 1) / (8 * n) - 1;
236
	uart->baud = n;
237
	return 0;
238
}
239
 
240
static int
241
bits(Uart *uart, int n)
242
{
243
	u32int *ap;
244
	int set;
245
 
246
	ap = (u32int*)uart->regs;
247
	switch(n){
248
	case 7:
249
		set = Bits7;
250
		break;
251
	case 8:
252
		set = Bits8;
253
		break;
254
	default:
255
		return -1;
256
	}
257
	ap[MuLcr] = (ap[MuLcr] & ~Bitsmask) | set;
258
	uart->bits = n;
259
	return 0;
260
}
261
 
262
static int
263
stop(Uart *uart, int n)
264
{
265
	if(n != 1)
266
		return -1;
267
	uart->stop = n;
268
	return 0;
269
}
270
 
271
static int
272
parity(Uart *uart, int n)
273
{
274
	if(n != 'n')
275
		return -1;
276
	uart->parity = n;
277
	return 0;
278
}
279
 
280
/*
281
 * cts/rts flow control
282
 *   need to bring signals to gpio pins before enabling this
283
 */
284
 
285
static void
286
modemctl(Uart *uart, int on)
287
{
288
	u32int *ap;
289
 
290
	ap = (u32int*)uart->regs;
291
	if(on)
292
		ap[MuCntl] |= CtsFlow;
293
	else
294
		ap[MuCntl] &= ~CtsFlow;
295
	uart->modem = on;
296
}
297
 
298
static void
299
rts(Uart *uart, int on)
300
{
301
	u32int *ap;
302
 
303
	ap = (u32int*)uart->regs;
304
	if(on)
305
		ap[MuMcr] &= ~RtsN;
306
	else
307
		ap[MuMcr] |= RtsN;
308
}
309
 
310
static long
311
status(Uart *uart, void *buf, long n, long offset)
312
{
313
	char *p;
314
 
315
	p = malloc(READSTR);
316
	if(p == nil)
317
		error(Enomem);
318
	snprint(p, READSTR,
319
		"b%d\n"
320
		"dev(%d) type(%d) framing(%d) overruns(%d) "
321
		"berr(%d) serr(%d)\n",
322
 
323
		uart->baud,
324
		uart->dev,
325
		uart->type,
326
		uart->ferr,
327
		uart->oerr,
328
		uart->berr,
329
		uart->serr
330
	);
331
	n = readstr(offset, buf, n, p);
332
	free(p);
333
 
334
	return n;
335
}
336
 
337
static void
338
donothing(Uart*, int)
339
{
340
}
341
 
342
void
343
putc(Uart*, int c)
344
{
345
	u32int *ap;
346
 
347
	ap = (u32int*)AUXREGS;
348
	while((ap[MuLsr] & TxRdy) == 0)
349
		;
350
	ap[MuIo] = c;
351
	while((ap[MuLsr] & TxRdy) == 0)
352
		;
353
}
354
 
355
int
356
getc(Uart*)
357
{
358
	u32int *ap;
359
 
360
	ap = (u32int*)AUXREGS;
361
	while((ap[MuLsr] & RxRdy) == 0)
362
		;
363
	return ap[MuIo] & 0xFF;
364
}
365
 
366
void
367
uartconsinit(void)
368
{
369
	Uart *uart;
370
	int n;
371
	char *p, *cmd;
372
 
373
	if((p = getconf("console")) == nil)
374
		return;
375
	n = strtoul(p, &cmd, 0);
376
	if(p == cmd)
377
		return;
378
	switch(n){
379
	default:
380
		return;
381
	case 0:
382
		uart = &miniuart;
383
		break;
384
	}
385
 
386
	if(!uart->enabled)
387
		(*uart->phys->enable)(uart, 0);
388
	uartctl(uart, "b9600 l8 pn s1");
389
	if(*cmd != '\0')
390
		uartctl(uart, cmd);
391
 
392
	consuart = uart;
393
	uart->console = 1;
394
}
395
 
396
PhysUart miniphysuart = {
397
	.name		= "miniuart",
398
	.pnp		= pnp,
399
	.enable		= enable,
400
	.disable	= disable,
401
	.kick		= kick,
402
	.dobreak	= dobreak,
403
	.baud		= baud,
404
	.bits		= bits,
405
	.stop		= stop,
406
	.parity		= parity,
407
	.modemctl	= donothing,
408
	.rts		= rts,
409
	.dtr		= donothing,
410
	.status		= status,
411
	.fifo		= donothing,
412
	.getc		= getc,
413
	.putc		= putc,
414
};
415
 
416
void
417
okay(int on)
418
{
419
	static int first;
420
 
421
	if(!first++)
422
		gpiosel(OkLed, Output);
423
	gpioout(OkLed, !on);
424
}