shithub: n900

ref: b611e99113cdebe713475694c49bdf17b8f7ff6c
dir: /sys/src/9/omap/uartomap.c/

View raw version
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
#include "../port/error.h"

enum {
	Rdll	= 0x00,
	Rrhr	= 0x00,
	Rthr	= 0x00,
	Rdlh	= 0x04,
	Rier	= 0x04,
		IErhr	= 1 << 0,
		IEthr	= 1 << 1,
		IEls	= 1 << 2,
		IEms	= 1 << 3,
	Riir	= 0x08,
		Ipending = 1 << 0,
		Imodem	= 0x00,
		Ithr	= 0x01,
		Irhr	= 0x02,
		Ils		= 0x03,
		Irxt	= 0x06,
		Ixoff	= 0x08,
		Icts	= 0x10,
		Imask 	= 0x1f,
	Rfcr	= 0x08,
		FCRen		= 1 << 0,
	Refr	= 0x08,
	Rlcr	= 0x0c,
	Rmcr	= 0x10,
	Rxon1	= 0x10,
	Rlsr	= 0x14,
		LSRrxempty	= 1 << 0,
		LSRrxover	= 1 << 1,
		LSRrxparity	= 1 << 2,
		LSRrxframe	= 1 << 3,
		LSRrxbreak	= 1 << 4,
		LSRtxempty	= 1 << 5,
		LSRtxshift	= 1 << 6,
		LSRrxstat	= 1 << 7,
	Rxon2	= 0x14,
	Rmsr	= 0x18,
	Rtcr	= 0x18,
	Rxoff1	= 0x18,
	Rspr	= 0x1c,
	Rtlr	= 0x1c,
	Rxoff2	= 0x1c,
	Rmdr1	= 0x20,
	Rmdr2	= 0x24,
	Rsysc	= 0x54,
		SCreset		= 1 << 1,
	Rsyss	= 0x58,
		SSreset		= 1 << 0,
};

#define csr32r(c, r) ((c)->io[(r)/4])
#define csr32w(c, r, w) ((c)->io[(r)/4] = (w))

typedef struct Ctlr Ctlr;
struct Ctlr {
	Lock;

	u32int *io;
	ulong irq;

	int ie;
};

extern PhysUart omapphysuart;

static Ctlr ctlr[] = {
	{ .io = (u32int*) PHYSUART1, .irq = IRQUART1, },
	{ .io = (u32int*) PHYSUART2, .irq = IRQUART2, },
	{ .io = (u32int*) PHYSUART3, .irq = IRQUART3, },
};

static Uart omapuart[] = {
	{
		.regs = &ctlr[0],
		.name = "uart1",
		.freq = 48000000,
		.phys = &omapphysuart,
		.next = &omapuart[1],
	},
	{
		.regs = &ctlr[1],
		.name = "uart2",
		.freq = 48000000,
		.phys = &omapphysuart,
		.next = &omapuart[2],
	},
	{
		.regs = &ctlr[2],
		.name = "uart3",
		.freq = 48000000,
		.phys = &omapphysuart,
		.next = nil,
	},
};

static Uart *
omapuartpnp(void)
{
	return omapuart;
}

static long
omapuartstatus(Uart *, void *, long, long)
{
	return 0;
}

static void
omapuartintr(Ureg *, void *arg)
{
	Uart *uart;
	Ctlr *ctlr;
	int lsr;
	char c;

	uart = arg;
	ctlr = uart->regs;

	ilock(ctlr);
	switch((csr32r(ctlr, Riir) >> 1) & Imask) {
	case Ithr:
		uartkick(uart);
		break;

	case Irhr:
		while((lsr = csr32r(ctlr, Rlsr)) & LSRrxempty) {
			c = csr32r(ctlr, Rrhr);

			if(lsr & LSRrxover) { uart->oerr++; break; }
			if(lsr & LSRrxparity) { uart->perr++; break; }
			if(lsr & LSRrxframe) { uart->ferr++; break; }

			uartrecv(uart, c);
		}

		break;
	}

	iunlock(ctlr);
}

static void
omapuartenable(Uart *uart, int ie)
{
	Ctlr *ctlr;
	int i;

	ctlr = uart->regs;
	ilock(ctlr);

	csr32w(ctlr, Rsysc, SCreset);
	for(i = 0; i < 100; i++) {
		if(csr32r(ctlr, Rsyss) & SSreset)
			break;
	}

	if(i == 100) {
		iunlock(ctlr);
		return;
	}

	csr32w(ctlr, Rfcr, FCRen);
	if(ie) {
		if(!ctlr->ie) {
			intrenable(ctlr->irq, omapuartintr, uart, 0, uart->name);
			ctlr->ie = 1;
		}

		csr32w(ctlr, Rier, IErhr);
	}

	iunlock(ctlr);
}

static void
omapuartdisable(Uart *uart)
{
	Ctlr *ctlr;

	ctlr = uart->regs;

	ilock(ctlr);
	csr32w(ctlr, Rier, 0);
	if(ctlr->ie) {
		intrdisable(ctlr->irq, omapuartintr, uart, 0, uart->name);
		ctlr->ie = 0;
	}

	iunlock(ctlr);
}

static void
omapuartkick(Uart *uart)
{
	Ctlr *ctlr;
	int i;

	ctlr = uart->regs;
	if(uart->blocked)
		return;

	for(i = 0; i < 128; i++) {
		if(csr32r(ctlr, Rlsr) & LSRtxempty) {
			if(uart->op >= uart->oe && uartstageoutput(uart) == 0)
				break;

			csr32w(ctlr, Rthr, *uart->op++);
		}
	}
}

static int
omapuartgetc(Uart *uart)
{
	Ctlr *ctlr;
	int i;

	ctlr = uart->regs;
	for(i = 0; i < 128; i++) {
		if(csr32r(ctlr, Rlsr) & LSRrxempty)
			break;

		delay(1);
	}

	return csr32r(ctlr, Rrhr);
}

static void
omapuartputc(Uart *uart, int c)
{
	Ctlr *ctlr;
	int i;

	ctlr = uart->regs;
	for(i = 0; i < 128; i++) {
		if(csr32r(ctlr, Rlsr) & LSRtxempty)
			break;

		delay(1);
	}

	csr32w(ctlr, Rthr, c);
}

static void omapuartnop(Uart *, int) {}
static int omapuartnope(Uart *, int) { return -1; }

PhysUart omapphysuart = {
	.name = "omap",

	.pnp = omapuartpnp,
	.enable = omapuartenable,
	.disable = omapuartdisable,
	.kick = omapuartkick,
	.status = omapuartstatus,
	.getc = omapuartgetc,
	.putc = omapuartputc,

	.dobreak = omapuartnop,
	.baud = omapuartnope,
	.bits = omapuartnope,
	.stop = omapuartnope,
	.parity = omapuartnope,
	.modemctl = omapuartnop,
	.rts = omapuartnop,
	.dtr = omapuartnop,
	.fifo = omapuartnop,
	.power = omapuartnop,
};

void
uartinit(void)
{
	Uart *u;
	Ctlr *c;
	char *p, *pe;
	ulong n;

	p = getconf("console");
	if(p == nil)
		return;

	n = strtoul(p, &pe, 0);
	if(pe == p || n > nelem(omapuart))
		return;

	u = &omapuart[n];
	c = omapuart[n].regs;
	if(!probeaddr((uintptr)c->io))
		return;

	(*u->phys->enable)(u, 0);

	consuart = u;
	consuart->console = 1;
	uartputs(kmesg.buf, kmesg.n);
}