u-boot-2013.07:UART分析

在文件/u-boot-2013.07 / arch / arm / include / asm / arch / s3c24x0.h中定义了有关UART寄存器的结构体,如下所示:

/* UART (see manual chapter 11) */
struct s3c24x0_uart {
    u32    ulcon;         /* ULCON:线路控制寄存器 */
    u32    ucon;          /* UCON:控制寄存器 */
    u32    ufcon;         /* UFCON:FIFO控制寄存器 */
    u32    umcon;         /* UMCON:MODEM控制寄存器 */
    u32    utrstat;       /* UTRSTAT:收发状态寄存器 */
    u32    uerstat;       /* UERSTAT:错误状态寄存器 */
    u32    ufstat;        /* UFSTAT:FIFO状态寄存器 */
    u32    umstat;        /* UMSTAT:MODEM状态寄存器 */
#ifdef __BIG_ENDIAN
    u8    res1[3];
    u8    utxh;
    u8    res2[3];
    u8    urxh;
#else /* Little Endian */
    u8    utxh;             /* UTXH:发送缓冲寄存器 */
    u8    res1[3];
    u8    urxh;             /* URXH:接收缓冲寄存器 */
    u8    res2[3];
#endif
    u32    ubrdiv;          /* UBRDIV:波特率分频寄存器 */
};


在设置寄存器时首先通过在/u-boot-2013.07 / arch / arm / include / asm / arch / s3c2440.h中定义的函数获取UART寄存器的首地址,如下所示:

static inline struct s3c24x0_uart
    *s3c24x0_get_base_uart(enum s3c24x0_uarts_nr n)
{
    return (struct s3c24x0_uart *)(S3C24X0_UART_BASE + (n * 0x4000));
}
/* 注:首地址获取后,根据结构体存储空间的分配,便可以知道UART所有相关的寄存器地址 */


文件一:/u-boot-2013.07 / include / serial.h

#ifndef __SERIAL_H__
#define __SERIAL_H__

#include <post.h>

struct serial_device {
	/* enough bytes to match alignment of following func pointer */
	char	name[16];

	int	(*start)(void);
	int	(*stop)(void);
	void	(*setbrg)(void);             /* 为串口设置波特率*/
	int	(*getc)(void);               /* 通过串口获得一个字符 */
	int	(*tstc)(void);
	void	(*putc)(const char c);       /* 通过串口输出字符c */
	void	(*puts)(const char *s);      /* 通过串口输出字符串s */
#if CONFIG_POST & CONFIG_SYS_POST_UART
	void	(*loop)(int);
#endif
	struct serial_device	*next;
};

void default_serial_puts(const char *s);

extern struct serial_device serial_smc_device;
extern struct serial_device serial_scc_device;
extern struct serial_device *default_serial_console(void);

#if	defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
	defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
	defined(CONFIG_405EX) || defined(CONFIG_440) || \
	defined(CONFIG_MB86R0x) || defined(CONFIG_MPC5xxx) || \
	defined(CONFIG_MPC83xx) || defined(CONFIG_MPC85xx) || \
	defined(CONFIG_MPC86xx) || defined(CONFIG_SYS_SC520) || \
	defined(CONFIG_TEGRA) || defined(CONFIG_SYS_COREBOOT) || \
	defined(CONFIG_MICROBLAZE)
extern struct serial_device serial0_device;
extern struct serial_device serial1_device;
#endif

extern struct serial_device eserial1_device;
extern struct serial_device eserial2_device;

extern void serial_register(struct serial_device *);
extern void serial_initialize(void);
extern void serial_stdio_init(void);
extern int serial_assign(const char *name);
extern void serial_reinit_all(void);

/* For usbtty */
#ifdef CONFIG_USB_TTY

extern int usbtty_getc(void);
extern void usbtty_putc(const char c);
extern void usbtty_puts(const char *str);
extern int usbtty_tstc(void);

#else

/* stubs */
#define usbtty_getc() 0
#define usbtty_putc(a)
#define usbtty_puts(a)
#define usbtty_tstc() 0

#endif /* CONFIG_USB_TTY */

#if defined(CONFIG_MPC512X)
extern struct stdio_dev *open_port(int num, int baudrate);
extern int close_port(int num);
extern int write_port(struct stdio_dev *port, char *buf);
extern int read_port(struct stdio_dev *port, char *buf, int size);
#endif

#endif




文件二:    /u-boot-2013.07 / drivers / serial / serial.c

#include <common.h>
#include <environment.h>
#include <serial.h>
#include <stdio_dev.h>
#include <post.h>
#include <linux/compiler.h>
#include <errno.h>

DECLARE_GLOBAL_DATA_PTR;

static struct serial_device *serial_devices;
static struct serial_device *serial_current;
/*
 * Table with supported baudrates (defined in config_xyz.h)
 */
static const unsigned long baudrate_table[] = CONFIG_SYS_BAUDRATE_TABLE;

/**
 * serial_null() - Void registration routine of a serial driver
 *
 * This routine implements a void registration routine of a serial
 * driver. The registration routine of a particular driver is aliased
 * to this empty function in case the driver is not compiled into
 * U-Boot.
 */
static void serial_null(void)
{
}

/**
 * on_baudrate() - Update the actual baudrate when the env var changes
 *
 * This will check for a valid baudrate and only apply it if valid.
 */
static int on_baudrate(const char *name, const char *value, enum env_op op,
	int flags)
{
	int i;
	int baudrate;

	switch (op) {
	case env_op_create:
	case env_op_overwrite:
		/*
		 * Switch to new baudrate if new baudrate is supported
		 */
		baudrate = simple_strtoul(value, NULL, 10);

		/* Not actually changing */
		if (gd->baudrate == baudrate)
			return 0;

		for (i = 0; i < ARRAY_SIZE(baudrate_table); ++i) {
			if (baudrate == baudrate_table[i])
				break;
		}
		if (i == ARRAY_SIZE(baudrate_table)) {
			if ((flags & H_FORCE) == 0)
				printf("## Baudrate %d bps not supported\n",
					baudrate);
			return 1;
		}
		if ((flags & H_INTERACTIVE) != 0) {
			printf("## Switch baudrate to %d"
				" bps and press ENTER ...\n", baudrate);
			udelay(50000);
		}

		gd->baudrate = baudrate;
#if defined(CONFIG_PPC) || defined(CONFIG_MCF52x2)
		gd->bd->bi_baudrate = baudrate;
#endif

		serial_setbrg();

		udelay(50000);

		if ((flags & H_INTERACTIVE) != 0)
			while (1) {
				if (getc() == '\r')
					break;
			}

		return 0;
	case env_op_delete:
		printf("## Baudrate may not be deleted\n");
		return 1;
	default:
		return 0;
	}
}
U_BOOT_ENV_CALLBACK(baudrate, on_baudrate);

/**
 * serial_initfunc() - Forward declare of driver registration routine
 * @name:	Name of the real driver registration routine.
 *
 * This macro expands onto forward declaration of a driver registration
 * routine, which is then used below in serial_initialize() function.
 * The declaration is made weak and aliases to serial_null() so in case
 * the driver is not compiled in, the function is still declared and can
 * be used, but aliases to serial_null() and thus is optimized away.
 */
#define serial_initfunc(name)					\
	void name(void)						\
		__attribute__((weak, alias("serial_null")));

serial_initfunc(mpc8xx_serial_initialize);
serial_initfunc(ns16550_serial_initialize);
serial_initfunc(pxa_serial_initialize);
serial_initfunc(s3c24xx_serial_initialize);
serial_initfunc(s5p_serial_initialize);
serial_initfunc(zynq_serial_initalize);
serial_initfunc(bfin_serial_initialize);
serial_initfunc(bfin_jtag_initialize);
serial_initfunc(mpc512x_serial_initialize);
serial_initfunc(uartlite_serial_initialize);
serial_initfunc(au1x00_serial_initialize);
serial_initfunc(asc_serial_initialize);
serial_initfunc(jz_serial_initialize);
serial_initfunc(mpc5xx_serial_initialize);
serial_initfunc(mpc8260_scc_serial_initialize);
serial_initfunc(mpc8260_smc_serial_initialize);
serial_initfunc(mpc85xx_serial_initialize);
serial_initfunc(iop480_serial_initialize);
serial_initfunc(leon2_serial_initialize);
serial_initfunc(leon3_serial_initialize);
serial_initfunc(marvell_serial_initialize);
serial_initfunc(amirix_serial_initialize);
serial_initfunc(bmw_serial_initialize);
serial_initfunc(cogent_serial_initialize);
serial_initfunc(cpci750_serial_initialize);
serial_initfunc(evb64260_serial_initialize);
serial_initfunc(ml2_serial_initialize);
serial_initfunc(sconsole_serial_initialize);
serial_initfunc(p3mx_serial_initialize);
serial_initfunc(altera_jtag_serial_initialize);
serial_initfunc(altera_serial_initialize);
serial_initfunc(atmel_serial_initialize);
serial_initfunc(lpc32xx_serial_initialize);
serial_initfunc(mcf_serial_initialize);
serial_initfunc(oc_serial_initialize);
serial_initfunc(sandbox_serial_initialize);
serial_initfunc(clps7111_serial_initialize);
serial_initfunc(imx_serial_initialize);
serial_initfunc(ixp_serial_initialize);
serial_initfunc(ks8695_serial_initialize);
serial_initfunc(lh7a40x_serial_initialize);
serial_initfunc(max3100_serial_initialize);
serial_initfunc(mxc_serial_initialize);
serial_initfunc(pl01x_serial_initialize);
serial_initfunc(s3c44b0_serial_initialize);
serial_initfunc(sa1100_serial_initialize);
serial_initfunc(sh_serial_initialize);

/**
 * serial_register() - Register serial driver with serial driver core
 * @dev:	Pointer to the serial driver structure
 *
 * This function registers the serial driver supplied via @dev with
 * serial driver core, thus making U-Boot aware of it and making it
 * available for U-Boot to use. On platforms that still require manual
 * relocation of constant variables, relocation of the supplied structure
 * is performed.
 */
void serial_register(struct serial_device *dev)
{
#ifdef CONFIG_NEEDS_MANUAL_RELOC
	if (dev->start)
		dev->start += gd->reloc_off;
	if (dev->stop)
		dev->stop += gd->reloc_off;
	if (dev->setbrg)
		dev->setbrg += gd->reloc_off;
	if (dev->getc)
		dev->getc += gd->reloc_off;
	if (dev->tstc)
		dev->tstc += gd->reloc_off;
	if (dev->putc)
		dev->putc += gd->reloc_off;
	if (dev->puts)
		dev->puts += gd->reloc_off;
#endif

	dev->next = serial_devices;
	serial_devices = dev;
}

/**
 * serial_initialize() - Register all compiled-in serial port drivers
 *
 * This function registers all serial port drivers that are compiled
 * into the U-Boot binary with the serial core, thus making them
 * available to U-Boot to use. Lastly, this function assigns a default
 * serial port to the serial core. That serial port is then used as a
 * default output.
 */
void serial_initialize(void)
{
	mpc8xx_serial_initialize();
	ns16550_serial_initialize();
	pxa_serial_initialize();
	s3c24xx_serial_initialize();
	s5p_serial_initialize();
	mpc512x_serial_initialize();
	bfin_serial_initialize();
	bfin_jtag_initialize();
	uartlite_serial_initialize();
	zynq_serial_initalize();
	au1x00_serial_initialize();
	asc_serial_initialize();
	jz_serial_initialize();
	mpc5xx_serial_initialize();
	mpc8260_scc_serial_initialize();
	mpc8260_smc_serial_initialize();
	mpc85xx_serial_initialize();
	iop480_serial_initialize();
	leon2_serial_initialize();
	leon3_serial_initialize();
	marvell_serial_initialize();
	amirix_serial_initialize();
	bmw_serial_initialize();
	cogent_serial_initialize();
	cpci750_serial_initialize();
	evb64260_serial_initialize();
	ml2_serial_initialize();
	sconsole_serial_initialize();
	p3mx_serial_initialize();
	altera_jtag_serial_initialize();
	altera_serial_initialize();
	atmel_serial_initialize();
	lpc32xx_serial_initialize();
	mcf_serial_initialize();
	oc_serial_initialize();
	sandbox_serial_initialize();
	clps7111_serial_initialize();
	imx_serial_initialize();
	ixp_serial_initialize();
	ks8695_serial_initialize();
	lh7a40x_serial_initialize();
	max3100_serial_initialize();
	mxc_serial_initialize();
	pl01x_serial_initialize();
	s3c44b0_serial_initialize();
	sa1100_serial_initialize();
	sh_serial_initialize();

	serial_assign(default_serial_console()->name);
}

/**
 * serial_stdio_init() - Register serial ports with STDIO core
 *
 * This function generates a proxy driver for each serial port driver.
 * These proxy drivers then register with the STDIO core, making the
 * serial drivers available as STDIO devices.
 */
void serial_stdio_init(void)
{
	struct stdio_dev dev;
	struct serial_device *s = serial_devices;

	while (s) {
		memset(&dev, 0, sizeof(dev));

		strcpy(dev.name, s->name);
		dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT;

		dev.start = s->start;
		dev.stop = s->stop;
		dev.putc = s->putc;
		dev.puts = s->puts;
		dev.getc = s->getc;
		dev.tstc = s->tstc;

		stdio_register(&dev);

		s = s->next;
	}
}

/**
 * serial_assign() - Select the serial output device by name
 * @name:	Name of the serial driver to be used as default output
 *
 * This function configures the serial output multiplexing by
 * selecting which serial device will be used as default. In case
 * the STDIO "serial" device is selected as stdin/stdout/stderr,
 * the serial device previously configured by this function will be
 * used for the particular operation.
 *
 * Returns 0 on success, negative on error.
 */
int serial_assign(const char *name)
{
	struct serial_device *s;

	for (s = serial_devices; s; s = s->next) {
		if (strcmp(s->name, name))
			continue;
		serial_current = s;
		return 0;
	}

	return -EINVAL;
}

/**
 * serial_reinit_all() - Reinitialize all compiled-in serial ports
 *
 * This function reinitializes all serial ports that are compiled
 * into U-Boot by calling their serial_start() functions.
 */
void serial_reinit_all(void)
{
	struct serial_device *s;

	for (s = serial_devices; s; s = s->next)
		s->start();
}

/**
 * get_current() - 返回指向当前所选择的串口的指针
 *
 * 该函数返回指向当前所选择串口的指针
 * 当前所选择的串口可以通过函数serial_assign()来改变
 * 为了避免该函数在代码复制前或在任何串口被配置前调用,该函数调
 * 用default_serial_console()来确定串口。否则,已配置的串口被返回。
 * 成功时返回指向当前所选择串口的指针,失败时返回NULL
 */
static struct serial_device *get_current(void)
{
	struct serial_device *dev;

	if (!(gd->flags & GD_FLG_RELOC))          /* 这两种情况下使用默认值*/
		dev = default_serial_console();
	else if (!serial_current)                
		dev = default_serial_console();
	else
		dev = serial_current;            /* 否则设为当前所选择的串口 */

	/* We must have a console device */
	if (!dev) {
#ifdef CONFIG_SPL_BUILD
		puts("Cannot find console\n");
		hang();
#else
		panic("Cannot find console\n");
#endif
	}

	return dev;      /* 返回指向所选择串口的指针 */
}

/**
 * serial_init() - Initialize currently selected serial port
 *
 * This function initializes the currently selected serial port. This
 * usually involves setting up the registers of that particular port,
 * enabling clock and such. This function uses the get_current() call
 * to determine which port is selected.
 *
 * Returns 0 on success, negative on error.
 */
int serial_init(void)
{
	return get_current()->start();
}

/**
 * serial_setbrg() - 为当前所选择的串口设置波特率
 *
 * 该函数用于为当前所选择的串口设置波特率,从串口驱动内的全局数据中检索波特率,
 * 该函数通过调用get_current()来确定选择了哪个串口。
 * Returns 0 on success, negative on error.
 */
void serial_setbrg(void)
{
	get_current()->setbrg();
}

/**
 * serial_getc() - 从当前所选择的串口中读取一个字符
 *
 * This function retrieves a character from currently selected serial
 * port. In case there is no character waiting on the serial port,
 * this function will block and wait for the character to appear. 
 * 该函数从当前所选择的串口中获取一个字符。该函数通过调用get_current()来确定选择了哪个串口。
 * 成功时返回字符,否则返回负值。
 */
int serial_getc(void)
{
	return get_current()->getc();
}

/**
 * serial_tstc() - Test if data is available on currently selected serial port
 *
 * This function tests if one or more characters are available on
 * currently selected serial port. This function never blocks. This
 * function uses the get_current() call to determine which port is
 * selected.
 *
 * Returns positive if character is available, zero otherwise.
 */
int serial_tstc(void)
{
	return get_current()->tstc();
}

/**
 * serial_putc() - Output character via currently selected serial port
 * @c:	Single character to be output from the serial port.
 *
 * This function outputs a character via currently selected serial
 * port. This character is passed to the serial port driver responsible
 * for controlling the hardware. The hardware may still be in process
 * of transmitting another character, therefore this function may block
 * for a short amount of time. This function uses the get_current()
 * call to determine which port is selected.
 * 该函数通过当前所选择的串口输出一个字符。该字符被传给负责控制硬件的串口驱动。
 * 该硬件可能仍需发送另外一个字符,所以要等待一小段时间。
 * 该函数通过get_current()确定选择哪一个串口。
 */
void serial_putc(const char c)
{
	get_current()->putc(c);
}

/**
 * serial_puts() - 通过当前所选择的串口输出字符串
 * @s:	Zero-terminated string to be output from the serial port.
 *
 * This function outputs a zero-terminated string via currently
 * selected serial port. This function behaves as an accelerator
 * in case the hardware can queue multiple characters for transfer.
 * The whole string that is to be output is available to the function
 * implementing the hardware manipulation. Transmitting the whole
 * string may take some time, thus this function may block for some
 * amount of time. This function uses the get_current() call to
 * determine which port is selected.
 */
void serial_puts(const char *s)
{
	get_current()->puts(s);
}

/**
 * default_serial_puts() - 通过循环调用serial_putc()来输出字符串
 * @s:	Zero-terminated string to be output from the serial port.
 *
 * This function outputs a zero-terminated string by calling serial_putc()
 * in a loop. Most drivers do not support queueing more than one byte for
 * transfer, thus this function precisely implements their serial_puts().
 *
 * To optimize the number of get_current() calls, this function only
 * calls get_current() once and then directly accesses the putc() call
 * of the &struct serial_device .
 */
void default_serial_puts(const char *s)
{
	struct serial_device *dev = get_current();
	while (*s)
		dev->putc(*s++);
}

#if CONFIG_POST & CONFIG_SYS_POST_UART
static const int bauds[] = CONFIG_SYS_BAUDRATE_TABLE;

/**
 * uart_post_test() - 用POST来测试当前所选择的串口
 * @flags:	POST framework flags
 *
 * Do a loopback test of the currently selected serial port. This
 * function is only useful in the context of the POST testing framwork.
 * The serial port is firstly configured into loopback mode and then
 * characters are sent through it.
 *
 * Returns 0 on success, value otherwise.
 */
/* Mark weak until post/cpu/.../uart.c migrate over */
__weak
int uart_post_test(int flags)
{
	unsigned char c;
	int ret, saved_baud, b;
	struct serial_device *saved_dev, *s;
	bd_t *bd = gd->bd;

	/* Save current serial state */
	ret = 0;
	saved_dev = serial_current;
	saved_baud = bd->bi_baudrate;

	for (s = serial_devices; s; s = s->next) {
		/* If this driver doesn't support loop back, skip it */
		if (!s->loop)
			continue;

		/* Test the next device */
		serial_current = s;

		ret = serial_init();
		if (ret)
			goto done;

		/* Consume anything that happens to be queued */
		while (serial_tstc())
			serial_getc();

		/* Enable loop back */
		s->loop(1);

		/* Test every available baud rate */
		for (b = 0; b < ARRAY_SIZE(bauds); ++b) {
			bd->bi_baudrate = bauds[b];
			serial_setbrg();

			/*
			 * Stick to printable chars to avoid issues:
			 *  - terminal corruption
			 *  - serial program reacting to sequences and sending
			 *    back random extra data
			 *  - most serial drivers add in extra chars (like \r\n)
			 */
			for (c = 0x20; c < 0x7f; ++c) {
				/* Send it out */
				serial_putc(c);

				/* Make sure it's the same one */
				ret = (c != serial_getc());
				if (ret) {
					s->loop(0);
					goto done;
				}

				/* Clean up the output in case it was sent */
				serial_putc('\b');
				ret = ('\b' != serial_getc());
				if (ret) {
					s->loop(0);
					goto done;
				}
			}
		}

		/* Disable loop back */
		s->loop(0);

		/* XXX: There is no serial_stop() !? */
		if (s->stop)
			s->stop();
	}

 done:
	/* Restore previous serial state */
	serial_current = saved_dev;
	bd->bi_baudrate = saved_baud;
	serial_reinit_all();
	serial_setbrg();

	return ret;
}
#endif


文件二:    /u-boot-2013.07 / drivers / serial / serial_s3c24x0.c

#include <common.h>
#include <linux/compiler.h>
#include <asm/arch/s3c24x0_cpu.h>

DECLARE_GLOBAL_DATA_PTR;

#ifdef CONFIG_SERIAL1
#define UART_NR	S3C24X0_UART0

#elif defined(CONFIG_SERIAL2)
#define UART_NR	S3C24X0_UART1

#elif defined(CONFIG_SERIAL3)
#define UART_NR	S3C24X0_UART2

#else
#error "Bad: you didn't configure serial ..."
#endif

#include <asm/io.h>
#include <serial.h>

/* Multi serial device functions */
#define DECLARE_S3C_SERIAL_FUNCTIONS(port) \
	int s3serial##port##_init(void) \
	{ \
		return serial_init_dev(port); \
	} \
	void s3serial##port##_setbrg(void) \
	{ \
		serial_setbrg_dev(port); \
	} \
	int s3serial##port##_getc(void) \
	{ \
		return serial_getc_dev(port); \
	} \
	int s3serial##port##_tstc(void) \
	{ \
		return serial_tstc_dev(port); \
	} \
	void s3serial##port##_putc(const char c) \
	{ \
		serial_putc_dev(port, c); \
	} \
	void s3serial##port##_puts(const char *s) \
	{ \
		serial_puts_dev(port, s); \
	}

#define INIT_S3C_SERIAL_STRUCTURE(port, __name) {	\
	.name	= __name,				\
	.start	= s3serial##port##_init,		\
	.stop	= NULL,					\
	.setbrg	= s3serial##port##_setbrg,		\
	.getc	= s3serial##port##_getc,		\
	.tstc	= s3serial##port##_tstc,		\
	.putc	= s3serial##port##_putc,		\
	.puts	= s3serial##port##_puts,		\
}

#ifdef CONFIG_HWFLOW
static int hwflow;
#endif

/* 设置指定串口硬件的UART波特率分频寄存器 */
void _serial_setbrg(const int dev_index)
{
        /* 获取UART所有寄存器的地址 */
        struct s3c24x0_uart *uart = s3c24x0_get_base_uart(dev_index);
	unsigned int reg = 0;
	int i;

	/* 根据UART时钟频率和波特率计算波特率分频值,UBRDIV=(int)(UART时钟频率/16/波特率)- 1 */
	reg = get_PCLK() / (16 * gd->baudrate) - 1;

	writel(reg, &uart->ubrdiv);   /* 设置UBRDIV */
	for (i = 0; i < 100; i++)
		/* Delay */ ;
}

static inline void serial_setbrg_dev(unsigned int dev_index)
{
	_serial_setbrg(dev_index);
}

/* 
 * 初始化串口:8位数据位,1位停止位,无起始位,无校验位,波特率
 */
static int serial_init_dev(const int dev_index)
{
	struct s3c24x0_uart *uart = s3c24x0_get_base_uart(dev_index); /* 获取UART所有寄存器的地址 */

#ifdef CONFIG_HWFLOW
	hwflow = 0;	/* turned off by default */
#endif

	/* FIFO enable, Tx/Rx FIFO clear */
	writel(0x07, &uart->ufcon);        /* 设置UFCON = 0X07 */
	writel(0x0, &uart->umcon);         /* 设置UMCON = 0X0 */

	/* Normal,No parity,1 stop,8 bit */
	writel(0x3, &uart->ulcon);         /* 设置ULCON = 0X3 */
	/*
	 * tx=level,rx=edge,disable timeout int.,enable rx error int.,
	 * normal,interrupt or polling
	 */
	writel(0x245, &uart->ucon);        /* 设置UCON = 0X245 */

#ifdef CONFIG_HWFLOW
	writel(0x1, &uart->umcon);	/* rts up,设置UMCON = 0X1 */
#endif

	/* FIXME: This is sooooooooooooooooooo ugly */
#if defined(CONFIG_ARCH_GTA02_v1) || defined(CONFIG_ARCH_GTA02_v2)
	/* we need auto hw flow control on the gsm and gps port */
	if (dev_index == 0 || dev_index == 1)
		writel(0x10, &uart->umcon);  /* 设置UMCON = 0X10 */
#endif
	_serial_setbrg(dev_index);          /* 设置UBRDIV */

	return (0);
}

/*
 * 通过串口读一个字节。成功时返回所读字节,否则返回0.
 */
int _serial_getc(const int dev_index)
{
	struct s3c24x0_uart *uart = s3c24x0_get_base_uart(dev_index);/* 获取UART所有寄存器的地址 */

	while (!(readl(&uart->utrstat) & 0x1))
		/* 通过查询法循环等待待接收的字符到达接收移位寄存器中 */ ;

	return readb(&uart->urxh) & 0xff; /* 读取并返回URXH中的一字节内容 */
}

/* 通过指定的串口接收一个字节 */
static inline int serial_getc_dev(unsigned int dev_index)
{
	return _serial_getc(dev_index);
}

#ifdef CONFIG_HWFLOW
int hwflow_onoff(int on)
{
	switch (on) {
	case 0:
	default:
		break;		/* return current */
	case 1:
		hwflow = 1;	/* turn on */
		break;
	case -1:
		hwflow = 0;	/* turn off */
		break;
	}
	return hwflow;
}
#endif

#ifdef CONFIG_MODEM_SUPPORT
static int be_quiet = 0;
void disable_putc(void)
{
	be_quiet = 1;
}

void enable_putc(void)
{
	be_quiet = 0;
}
#endif


/*
 * 通过串口输出一个字节.
 */
void _serial_putc(const char c, const int dev_index)
{
	struct s3c24x0_uart *uart = s3c24x0_get_base_uart(dev_index);/* 获取UART所有寄存器的地址 */
#ifdef CONFIG_MODEM_SUPPORT
	if (be_quiet)
		return;
#endif

	while (!(readl(&uart->utrstat) & 0x2))
		/* wait for room in the tx FIFO */ ;

#ifdef CONFIG_HWFLOW
	while (hwflow && !(readl(&uart->umstat) & 0x1))
		/* Wait for CTS up */ ;
#endif

	writeb(c, &uart->utxh); /* 通过向UTXH中中写一字节内容以便自动通过串口输出 */

	/* If \n, also do \r */
	if (c == '\n')
		serial_putc('\r');
}

/* 通过指定的串口硬件输出一个字节 */
static inline void serial_putc_dev(unsigned int dev_index, const char c)
{
	_serial_putc(c, dev_index);
}

/*
 * 检测接收移位寄存器中是否收到一个字节
 */
int _serial_tstc(const int dev_index)
{
	struct s3c24x0_uart *uart = s3c24x0_get_base_uart(dev_index);/* 获取UART所有寄存器的地址 */

	return readl(&uart->utrstat) & 0x1;  /*读取并返回UTRSTAT[0]即接收缓冲区状态:1为接收到数据,0为未收到*/
}

static inline int serial_tstc_dev(unsigned int dev_index)
{
	return _serial_tstc(dev_index);
}

/* 通过指定的串口硬件来输出字符串 */
void _serial_puts(const char *s, const int dev_index)
{
	while (*s) {
		_serial_putc(*s++, dev_index);
	}
}

static inline void serial_puts_dev(int dev_index, const char *s)
{
	_serial_puts(s, dev_index);
}

DECLARE_S3C_SERIAL_FUNCTIONS(0);
struct serial_device s3c24xx_serial0_device =
INIT_S3C_SERIAL_STRUCTURE(0, "s3ser0");
DECLARE_S3C_SERIAL_FUNCTIONS(1);
struct serial_device s3c24xx_serial1_device =
INIT_S3C_SERIAL_STRUCTURE(1, "s3ser1");
DECLARE_S3C_SERIAL_FUNCTIONS(2);
struct serial_device s3c24xx_serial2_device =
INIT_S3C_SERIAL_STRUCTURE(2, "s3ser2");

__weak struct serial_device *default_serial_console(void)
{
#if defined(CONFIG_SERIAL1)
	return &s3c24xx_serial0_device;
#elif defined(CONFIG_SERIAL2)
	return &s3c24xx_serial1_device;
#elif defined(CONFIG_SERIAL3)
	return &s3c24xx_serial2_device;
#else
#error "CONFIG_SERIAL? missing."
#endif
}

void s3c24xx_serial_initialize(void)
{
	serial_register(&s3c24xx_serial0_device);  /* 注册串口硬件:UART0 */
	serial_register(&s3c24xx_serial1_device);  /* 注册串口硬件:UART1 */
	serial_register(&s3c24xx_serial2_device);  /* 注册串口硬件:UART2 */
}







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值