Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b94ba032 authored by Tomasz Figa's avatar Tomasz Figa Committed by Greg Kroah-Hartman
Browse files

serial: samsung: Add support for early console



This patch adds support for early console initialized from device tree
and kernel command line to all variants of Samsung serial driver.

Signed-off-by: default avatarTomasz Figa <t.figa@samsung.com>
[mszyprow: added support for command line based initialization,
           fixed comments, added documentation]
Signed-off-by: default avatarMarek Szyprowski <m.szyprowski@samsung.com>
Reviewed-by: default avatarAlim Akhtar <alim.akhtar@samsung.com>
Tested-by: default avatarAlim Akhtar <alim.akhtar@samsung.com>
Tested-by: default avatarChanwoo Choi <cw00.choi@samsung.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 8b6ff84c
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -970,6 +970,18 @@ bytes respectively. Such letter suffixes can also be entirely omitted.

		smh	Use ARM semihosting calls for early console.

		s3c2410,<addr>
		s3c2412,<addr>
		s3c2440,<addr>
		s3c6400,<addr>
		s5pv210,<addr>
		exynos4210,<addr>
			Use early console provided by serial driver available
			on Samsung SoCs, requires selecting proper type and
			a correct base address of the selected UART port. The
			serial port must already be setup and configured.
			Options are not yet supported.

	earlyprintk=	[X86,SH,BLACKFIN,ARM,M68k]
			earlyprintk=vga
			earlyprintk=efi
+1 −0
Original line number Diff line number Diff line
@@ -241,6 +241,7 @@ config SERIAL_SAMSUNG
	tristate "Samsung SoC serial support"
	depends on PLAT_SAMSUNG || ARCH_EXYNOS
	select SERIAL_CORE
	select SERIAL_EARLYCON
	help
	  Support for the on-chip UARTs on the Samsung S3C24XX series CPUs,
	  providing /dev/ttySAC0, 1 and 2 (note, some machines may not
+103 −0
Original line number Diff line number Diff line
@@ -2403,6 +2403,109 @@ static struct platform_driver samsung_serial_driver = {

module_platform_driver(samsung_serial_driver);

/*
 * Early console.
 */

struct samsung_early_console_data {
	u32 txfull_mask;
};

static void samsung_early_busyuart(struct uart_port *port)
{
	while (!(readl(port->membase + S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXFE))
		;
}

static void samsung_early_busyuart_fifo(struct uart_port *port)
{
	struct samsung_early_console_data *data = port->private_data;

	while (readl(port->membase + S3C2410_UFSTAT) & data->txfull_mask)
		;
}

static void samsung_early_putc(struct uart_port *port, int c)
{
	if (readl(port->membase + S3C2410_UFCON) & S3C2410_UFCON_FIFOMODE)
		samsung_early_busyuart_fifo(port);
	else
		samsung_early_busyuart(port);

	writeb(c, port->membase + S3C2410_UTXH);
}

static void samsung_early_write(struct console *con, const char *s, unsigned n)
{
	struct earlycon_device *dev = con->data;

	uart_console_write(&dev->port, s, n, samsung_early_putc);
}

static int __init samsung_early_console_setup(struct earlycon_device *device,
					      const char *opt)
{
	if (!device->port.membase)
		return -ENODEV;

	device->con->write = samsung_early_write;
	return 0;
}

/* S3C2410 */
static struct samsung_early_console_data s3c2410_early_console_data = {
	.txfull_mask = S3C2410_UFSTAT_TXFULL,
};

static int __init s3c2410_early_console_setup(struct earlycon_device *device,
					      const char *opt)
{
	device->port.private_data = &s3c2410_early_console_data;
	return samsung_early_console_setup(device, opt);
}
OF_EARLYCON_DECLARE(s3c2410, "samsung,s3c2410-uart",
			s3c2410_early_console_setup);
EARLYCON_DECLARE(s3c2410, s3c2410_early_console_setup);

/* S3C2412, S3C2440, S3C64xx */
static struct samsung_early_console_data s3c2440_early_console_data = {
	.txfull_mask = S3C2440_UFSTAT_TXFULL,
};

static int __init s3c2440_early_console_setup(struct earlycon_device *device,
					      const char *opt)
{
	device->port.private_data = &s3c2440_early_console_data;
	return samsung_early_console_setup(device, opt);
}
OF_EARLYCON_DECLARE(s3c2412, "samsung,s3c2412-uart",
			s3c2440_early_console_setup);
OF_EARLYCON_DECLARE(s3c2440, "samsung,s3c2440-uart",
			s3c2440_early_console_setup);
OF_EARLYCON_DECLARE(s3c6400, "samsung,s3c6400-uart",
			s3c2440_early_console_setup);
EARLYCON_DECLARE(s3c2412, s3c2440_early_console_setup);
EARLYCON_DECLARE(s3c2440, s3c2440_early_console_setup);
EARLYCON_DECLARE(s3c6400, s3c2440_early_console_setup);

/* S5PV210, EXYNOS */
static struct samsung_early_console_data s5pv210_early_console_data = {
	.txfull_mask = S5PV210_UFSTAT_TXFULL,
};

static int __init s5pv210_early_console_setup(struct earlycon_device *device,
					      const char *opt)
{
	device->port.private_data = &s5pv210_early_console_data;
	return samsung_early_console_setup(device, opt);
}
OF_EARLYCON_DECLARE(s5pv210, "samsung,s5pv210-uart",
			s5pv210_early_console_setup);
OF_EARLYCON_DECLARE(exynos4210, "samsung,exynos4210-uart",
			s5pv210_early_console_setup);
EARLYCON_DECLARE(s5pv210, s5pv210_early_console_setup);
EARLYCON_DECLARE(exynos4210, s5pv210_early_console_setup);

MODULE_ALIAS("platform:samsung-uart");
MODULE_DESCRIPTION("Samsung SoC Serial port driver");
MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");