NetBSD-5.0.2/sys/arch/arm/imx/imxuart.c

Compare this file to the similar file:
Show the results in this format:

/* $Id: imxuart.c,v 1.3 2008/06/30 00:46:41 perry Exp $ */
#include <sys/types.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/conf.h>

#include <arm/armreg.h>

#include <sys/tty.h>
#include <sys/termios.h>
#include <dev/cons.h>

#include <machine/bus.h>
#include <arm/imx/imx31var.h>
#include <arm/imx/imxuartreg.h>
#include <arm/imx/imxuartvar.h>
#include <evbarm/imx31/imx31lk_reg.h>

#define IMXUART_UNIT_MASK	0x7ffff
#define IMXUART_DIALOUT_MASK	0x80000

#define IMXUART_UNIT(dev)	(minor(dev) & IMXUART_UNIT_MASK)
#define IMXUART_DIALOUT(dev)	(minor(dev) & IMXUART_DIALOUT_MASK)



#define __TRACE	imxuart_puts(&imxuart_softc, __func__ )

extern struct bus_space imx31_bs_tag;

imxuart_softc_t imxuart_softc = { { 0, }, };

uint32_t imxuart_snapshot_data[32];
const char *imxuart_test_string = 
	"0123456789012345678901234567890123456789\r\n";


cons_decl(imxuart);
static struct consdev imxuartcntab = cons_init(imxuart);

#ifdef NOTYET
dev_type_open(imxuartopen);
dev_type_close(imxuartclose);
dev_type_read(imxuartread);
dev_type_write(imxuartwrite);
dev_type_ioctl(imxuartioctl);
dev_type_stop(imxuartstop); 
dev_type_tty(imxuarttty);
dev_type_poll(imxuartpoll);
const struct cdevsw imxuart_cdevsw = {
        imxuartopen, imxuartclose, imxuartread, imxuartwrite,
	imxuartioctl, imxuartstop, imxuarttty, imxuartpoll,
	nommap, ttykqfilter, D_TTY
}; 
#else
const struct cdevsw imxuart_cdevsw = {
        nullopen, nullclose, nullread, nullwrite,
	nullioctl, nullstop, notty, nullpoll,
	nommap, nullkqfilter, D_TTY
}; 
#endif


int  imxuart_cnattach(bus_space_tag_t, bus_addr_t, int, int, int, tcflag_t);
int  imxuart_puts(imxuart_softc_t *, const char *);
int  imxuart_putchar(imxuart_softc_t *, int);
int  imxuart_getchar(imxuart_softc_t *);

static int  imxuart_urxd_brk(void);
static void imxuart_urxd_err(imxuart_softc_t *, uint32_t);

static int imxuart_match(struct device *, struct cfdata *, void *);
static void imxuart_attach(struct device *, struct device *, void *);

static void imxuart_start(struct tty *);
static int  imxuart_param(struct tty *, struct termios *);
static void imxuart_shutdownhook(void *arg);

CFATTACH_DECL(imxuart, sizeof(struct imxuart_softc),
    imxuart_match, imxuart_attach, NULL, NULL);


/*
 * disable the specified IMX UART interrupt in softc
 * return -1 on error
 * else return previous enabled state
 */
static __inline int
imxuart_intrspec_dis(imxuart_softc_t *sc, imxuart_intrix_t ix)
{
	const imxuart_intrspec_t *spec = &imxuart_intrspec_tab[ix];
	uint32_t v;
	uint32_t b;
	const uint32_t syncbit = 1 << 31;
	uint n;

	if (ix >= IMXUART_INTRSPEC_TAB_SZ)
		return -1;

	v = (1 << ix);
	if ((sc->sc_intrspec_enb & v) == 0)
		return 0;
	sc->sc_intrspec_enb &= ~v;

	n = spec->enb_reg;
	b = spec->enb_bit;
	v = sc->sc_ucr[n];
	v &= ~b;
	v |= syncbit;
	sc->sc_ucr[n] = v;

	n = spec->flg_reg;
	b = spec->flg_bit;
	v = sc->sc_usr[n];
	v &= ~b;
	v |= syncbit;
	sc->sc_usr[n] = v;

	return 1;
}

/*
 * enable the specified IMX UART interrupt in softc
 * return -1 on error
 * else return previous enabled state
 */
static __inline int
imxuart_intrspec_enb(imxuart_softc_t *sc, imxuart_intrix_t ix)
{
	const imxuart_intrspec_t *spec = &imxuart_intrspec_tab[ix];
	uint32_t v;
	uint n;
	const uint32_t syncbit = 1 << 31;

	if (ix >= IMXUART_INTRSPEC_TAB_SZ)
		return -1;

	v = (1 << ix);
	if ((sc->sc_intrspec_enb & v) != 0)
		return 1;
	sc->sc_intrspec_enb |= v;


	n = spec->enb_reg;
	v = spec->enb_bit;
	v |= syncbit;
	sc->sc_ucr[n] |= v;

	n = spec->flg_reg;
	v = spec->flg_bit;
	v |= syncbit;
	sc->sc_usr[n] |= v;

	return 0;
}

/*
 * sync softc interrupt spec to UART Control regs
 */
static __inline void
imxuart_intrspec_sync(imxuart_softc_t *sc)
{
	int i;
	uint32_t r;
	uint32_t v;
	const uint32_t syncbit = 1 << 31;
	const uint32_t mask[4] = { 
		IMXUART_INTRS_UCR1, 
		IMXUART_INTRS_UCR2, 
		IMXUART_INTRS_UCR3, 
		IMXUART_INTRS_UCR4
	};

	for (i=0; i < 4; i++) {
		v = sc->sc_ucr[i];
		if (v & syncbit) {
			v &= ~syncbit;
			sc->sc_ucr[i] = v;
			r = bus_space_read_4(sc->sc_bt, sc->sc_bh, IMX_UCRn(i));
			r &= ~mask[i];
			r |= v;
			bus_space_write_4(sc->sc_bt, sc->sc_bh, IMX_UCRn(i), r);
		}
	}
}


int
imxuart_init(imxuart_softc_t *sc, uint bh)
{
	if (sc == 0)
		sc = &imxuart_softc;
	sc->sc_init_cnt++;
	cn_tab = &imxuartcntab;
	sc->sc_bt = &imx31_bs_tag;
	sc->sc_bh = bh;

	memset(&sc->sc_errors, 0, sizeof(sc->sc_errors));

	return 0;
}

int
imxuart_puts(imxuart_softc_t *sc, const char *s)
{
	char c;
	int err = -2;

	for(;;) {
		c = *s++;
		if (c == '\0')
			break;
		err = imxuart_putchar(sc, c);
	}
	return err;
}

int
imxuart_putchar(imxuart_softc_t *sc, int c)
{
	uint32_t r;

	for (;;) {
		r = bus_space_read_4(sc->sc_bt, sc->sc_bh, IMX_UTS);
		if ((r & IMX_UTS_TXFUL) == 0)
			break;
	}

	r = (uint32_t)c & IMX_UTXD_TX_DATA;
	bus_space_write_4(sc->sc_bt, sc->sc_bh, IMX_UTXD, r);

	return 0;
}

int
imxuart_getchar(imxuart_softc_t *sc)
{
	uint32_t r;
	int c;

	for(;;) {
		r = bus_space_read_4(sc->sc_bt, sc->sc_bh, IMX_URXD);
		if (r & IMX_URXD_ERR) {
			imxuart_urxd_err(sc, r);
			continue;
		}
		if (r & IMX_URXD_CHARDY) {
			c = (int)(r & IMX_URXD_RX_DATA);
			break;
		}
	}

	return c;
}

static int
imxuart_urxd_brk(void)
{
#ifdef DDB
	if (cn_tab == &imxuartcntab) {
		Debugger();
		return 0;
	}
#endif
	return 1;
}

static void
imxuart_urxd_err(imxuart_softc_t *sc, uint32_t r)
{
	if (r & IMX_URXD_BRK)
		if (imxuart_urxd_brk() == 0)
			return;

	sc->sc_errors.err++;
	if (r & IMX_URXD_BRK)
		sc->sc_errors.brk++;
	if (r & IMX_URXD_PRERR)
		sc->sc_errors.prerr++;
	if (r & IMX_URXD_FRMERR)
		sc->sc_errors.frmerr++;
	if (r & IMX_URXD_OVRRUN)
		sc->sc_errors.ovrrun++;
}

static int
imxuart_snapshot(imxuart_softc_t *sc, uint32_t *p)
{
	int i;
	const uint r[] = {	IMX_URXD, IMX_UTXD, IMX_UCR1, IMX_UCR2,
			IMX_UCR3, IMX_UCR4, IMX_UFCR, IMX_USR1,
			IMX_USR2, IMX_UESC, IMX_UTIM, IMX_UBIR,
			IMX_UBMR, IMX_UBRC, IMX_ONEMS, IMX_UTS };

	for (i=0; i < ((sizeof(r)/sizeof(r[0]))); i++) {
		*p++ = sc->sc_bh + r[i];
		*p++ = bus_space_read_4(sc->sc_bt, sc->sc_bh, r[i]);
	}
	return 0;
}

int
imxuart_test(void)
{
	imxuart_softc_t *sc = &imxuart_softc;
	int n;
	int err;
	
	err = imxuart_init(sc, 1);
	if (err != 0)
		return err;

	if (0) {
		extern u_int cpufunc_id(void);
		err = cpufunc_id();
		return err;
	}

#if 0
	err = imxuart_snapshot(sc, imxuart_snapshot_data);
	if (err != 0)
		return err;
#endif


	err = imxuart_putchar(sc, 'x');
	if (err != 0)
		return err;

	for (n=100; n--; ) {
		err = imxuart_puts(sc, imxuart_test_string);
		if (err != 0)
			break;
	}

	err = imxuart_snapshot(sc, imxuart_snapshot_data);
	if (err != 0)
		return err;

	return err;
}

static int
imxuart_match(struct device *parent, struct cfdata *cf, void *aux)
{
	struct aips_attach_args * const aipsa = aux;

	switch (aipsa->aipsa_addr) {
	case IMX_UART1_BASE:
	case IMX_UART2_BASE:
	case IMX_UART3_BASE:
	case IMX_UART4_BASE:
	case IMX_UART5_BASE:
		return 1;
	default:
		return 0;
	}
}

static void
imxuart_attach(struct device *parent, struct device *self, void *aux)
{
	imxuart_softc_t *sc = (void *)self;
	struct aips_attach_args * const aipsa = aux;
	struct tty *tp;

	sc->sc_bt = aipsa->aipsa_memt;
	sc->sc_addr = aipsa->aipsa_addr;
	sc->sc_size = aipsa->aipsa_size;
	sc->sc_intr = aipsa->aipsa_intr;

	sc->sc_tty = tp = ttymalloc();
	tp->t_oproc = imxuart_start;
	tp->t_param = imxuart_param;
	tty_attach(tp);
	
	shutdownhook_establish(imxuart_shutdownhook, sc);

	printf("\n");
}

void
imxuartcnprobe(struct consdev *cp)
{
	int major;

	__TRACE;
	major = cdevsw_lookup_major(&imxuart_cdevsw);
	cp->cn_dev = makedev(major, 0);			/* XXX unit 0 */
	cp->cn_pri = CN_REMOTE;
}

static void
imxuart_start(struct tty *tp)
{
	__TRACE;
}

static int
imxuart_param(struct tty *tp, struct termios *termios)
{
	__TRACE;
	return 0;
}

static void
imxuart_shutdownhook(void *arg)
{
	__TRACE;
}

void
imxuartcninit(struct consdev *cp)
{
	__TRACE;
}

int
imxuartcngetc(dev_t dev)
{
	struct imxuart_softc *sc;
	uint unit;
	int c;

	unit = IMXUART_UNIT(dev);
	if (unit != 0)
		return 0;
	sc = &imxuart_softc;
	c = imxuart_getchar(sc);
	return c;
}

void
imxuartcnputc(dev_t dev, int c)
{
	(void)imxuart_putchar(&imxuart_softc, c);
}

void
imxuartcnpollc(dev_t dev, int mode)
{
	/* always polled for now */
}
int
imxuart_cnattach(bus_space_tag_t iot, bus_addr_t iobase,
	int rate, int frequency, int type, tcflag_t cflag)
{
	cn_tab = &imxuartcntab;
	return 0;
}