2014-04-19 02:19:55 +04:00
/*
* Copyright ( C ) 2014 Linaro Ltd .
* Author : Rob Herring < robh @ kernel . org >
*
* Based on 8250 earlycon :
* ( c ) Copyright 2004 Hewlett - Packard Development Company , L . P .
* Bjorn Helgaas < bjorn . helgaas @ hp . com >
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*/
2015-03-09 23:27:21 +03:00
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2014-04-19 02:19:55 +04:00
# include <linux/console.h>
# include <linux/kernel.h>
# include <linux/init.h>
# include <linux/io.h>
# include <linux/serial_core.h>
2014-03-27 17:06:16 +04:00
# include <linux/sizes.h>
# include <linux/mod_devicetable.h>
2014-04-19 02:19:55 +04:00
# ifdef CONFIG_FIX_EARLYCON_MEM
# include <asm/fixmap.h>
# endif
# include <asm/serial.h>
static struct console early_con = {
2014-06-12 21:52:44 +04:00
. name = " uart " , /* 8250 console switch requires this name */
2014-04-19 02:19:55 +04:00
. flags = CON_PRINTBUFFER | CON_BOOT ,
. index = - 1 ,
} ;
static struct earlycon_device early_console_dev = {
. con = & early_con ,
} ;
2015-03-09 23:27:21 +03:00
extern struct earlycon_id __earlycon_table [ ] ;
static const struct earlycon_id __earlycon_table_sentinel
__used __section ( __earlycon_table_end ) ;
2014-03-27 17:06:16 +04:00
static const struct of_device_id __earlycon_of_table_sentinel
__used __section ( __earlycon_of_table_end ) ;
2014-04-19 02:19:55 +04:00
static void __iomem * __init earlycon_map ( unsigned long paddr , size_t size )
{
void __iomem * base ;
# ifdef CONFIG_FIX_EARLYCON_MEM
set_fixmap_io ( FIX_EARLYCON_MEM_BASE , paddr & PAGE_MASK ) ;
base = ( void __iomem * ) __fix_to_virt ( FIX_EARLYCON_MEM_BASE ) ;
base + = paddr & ~ PAGE_MASK ;
# else
base = ioremap ( paddr , size ) ;
# endif
if ( ! base )
pr_err ( " %s: Couldn't map 0x%llx \n " , __func__ ,
( unsigned long long ) paddr ) ;
return base ;
}
serial: earlycon: Refactor parse_options into serial core
Prepare to support console-defined matching; refactor the command
line parameter string processing from parse_options() into a
new core function, uart_parse_earlycon(), which decodes command line
parameters of the form:
earlycon=<name>,io|mmio|mmio32,<addr>,<options>
console=<name>,io|mmio|mmio32,<addr>,<options>
earlycon=<name>,0x<addr>,<options>
console=<name>,0x<addr>,<options>
Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2015-03-01 19:05:46 +03:00
static int __init parse_options ( struct earlycon_device * device , char * options )
2014-04-19 02:19:55 +04:00
{
struct uart_port * port = & device - > port ;
serial: earlycon: Refactor parse_options into serial core
Prepare to support console-defined matching; refactor the command
line parameter string processing from parse_options() into a
new core function, uart_parse_earlycon(), which decodes command line
parameters of the form:
earlycon=<name>,io|mmio|mmio32,<addr>,<options>
console=<name>,io|mmio|mmio32,<addr>,<options>
earlycon=<name>,0x<addr>,<options>
console=<name>,0x<addr>,<options>
Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2015-03-01 19:05:46 +03:00
int length ;
2014-04-19 02:19:55 +04:00
unsigned long addr ;
serial: earlycon: Refactor parse_options into serial core
Prepare to support console-defined matching; refactor the command
line parameter string processing from parse_options() into a
new core function, uart_parse_earlycon(), which decodes command line
parameters of the form:
earlycon=<name>,io|mmio|mmio32,<addr>,<options>
console=<name>,io|mmio|mmio32,<addr>,<options>
earlycon=<name>,0x<addr>,<options>
console=<name>,0x<addr>,<options>
Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2015-03-01 19:05:46 +03:00
if ( uart_parse_earlycon ( options , & port - > iotype , & addr , & options ) )
return - EINVAL ;
2014-04-19 02:19:55 +04:00
serial: earlycon: Refactor parse_options into serial core
Prepare to support console-defined matching; refactor the command
line parameter string processing from parse_options() into a
new core function, uart_parse_earlycon(), which decodes command line
parameters of the form:
earlycon=<name>,io|mmio|mmio32,<addr>,<options>
console=<name>,io|mmio|mmio32,<addr>,<options>
earlycon=<name>,0x<addr>,<options>
console=<name>,0x<addr>,<options>
Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2015-03-01 19:05:46 +03:00
switch ( port - > iotype ) {
case UPIO_MEM32 :
2015-05-25 06:54:28 +03:00
case UPIO_MEM32BE :
serial: earlycon: Refactor parse_options into serial core
Prepare to support console-defined matching; refactor the command
line parameter string processing from parse_options() into a
new core function, uart_parse_earlycon(), which decodes command line
parameters of the form:
earlycon=<name>,io|mmio|mmio32,<addr>,<options>
console=<name>,io|mmio|mmio32,<addr>,<options>
earlycon=<name>,0x<addr>,<options>
console=<name>,0x<addr>,<options>
Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2015-03-01 19:05:46 +03:00
port - > regshift = 2 ; /* fall-through */
case UPIO_MEM :
2014-04-19 02:19:55 +04:00
port - > mapbase = addr ;
serial: earlycon: Refactor parse_options into serial core
Prepare to support console-defined matching; refactor the command
line parameter string processing from parse_options() into a
new core function, uart_parse_earlycon(), which decodes command line
parameters of the form:
earlycon=<name>,io|mmio|mmio32,<addr>,<options>
console=<name>,io|mmio|mmio32,<addr>,<options>
earlycon=<name>,0x<addr>,<options>
console=<name>,0x<addr>,<options>
Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2015-03-01 19:05:46 +03:00
break ;
case UPIO_PORT :
2014-04-19 02:19:55 +04:00
port - > iobase = addr ;
serial: earlycon: Refactor parse_options into serial core
Prepare to support console-defined matching; refactor the command
line parameter string processing from parse_options() into a
new core function, uart_parse_earlycon(), which decodes command line
parameters of the form:
earlycon=<name>,io|mmio|mmio32,<addr>,<options>
console=<name>,io|mmio|mmio32,<addr>,<options>
earlycon=<name>,0x<addr>,<options>
console=<name>,0x<addr>,<options>
Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2015-03-01 19:05:46 +03:00
break ;
default :
2014-04-19 02:19:55 +04:00
return - EINVAL ;
}
if ( options ) {
2014-05-01 04:48:29 +04:00
device - > baud = simple_strtoul ( options , NULL , 0 ) ;
2014-04-19 02:19:55 +04:00
length = min ( strcspn ( options , " " ) + 1 ,
( size_t ) ( sizeof ( device - > options ) ) ) ;
strlcpy ( device - > options , options , length ) ;
}
2015-05-25 06:54:28 +03:00
if ( port - > iotype = = UPIO_MEM | | port - > iotype = = UPIO_MEM32 | |
port - > iotype = = UPIO_MEM32BE )
2014-04-19 02:19:55 +04:00
pr_info ( " Early serial console at MMIO%s 0x%llx (options '%s') \n " ,
2015-05-25 06:54:28 +03:00
( port - > iotype = = UPIO_MEM ) ? " " :
( port - > iotype = = UPIO_MEM32 ) ? " 32 " : " 32be " ,
2014-04-19 02:19:55 +04:00
( unsigned long long ) port - > mapbase ,
device - > options ) ;
else
pr_info ( " Early serial console at I/O port 0x%lx (options '%s') \n " ,
port - > iobase ,
device - > options ) ;
return 0 ;
}
2015-03-09 23:27:21 +03:00
static int __init register_earlycon ( char * buf , const struct earlycon_id * match )
2014-04-19 02:19:55 +04:00
{
int err ;
struct uart_port * port = & early_console_dev . port ;
/* On parsing error, pass the options buf to the setup function */
2015-03-09 23:27:19 +03:00
if ( buf & & ! parse_options ( & early_console_dev , buf ) )
2014-04-19 02:19:55 +04:00
buf = NULL ;
2015-03-09 23:27:15 +03:00
port - > uartclk = BASE_BAUD * 16 ;
2014-04-19 02:19:55 +04:00
if ( port - > mapbase )
port - > membase = earlycon_map ( port - > mapbase , 64 ) ;
early_console_dev . con - > data = & early_console_dev ;
2015-03-09 23:27:21 +03:00
err = match - > setup ( & early_console_dev , buf ) ;
2014-04-19 02:19:55 +04:00
if ( err < 0 )
return err ;
if ( ! early_console_dev . con - > write )
return - ENODEV ;
register_console ( early_console_dev . con ) ;
return 0 ;
}
2014-03-27 17:06:16 +04:00
2015-03-09 23:27:21 +03:00
/**
* setup_earlycon - match and register earlycon console
* @ buf : earlycon param string
*
* Registers the earlycon console matching the earlycon specified
* in the param string @ buf . Acceptable param strings are of the form
2015-05-25 06:54:28 +03:00
* < name > , io | mmio | mmio32 | mmio32be , < addr > , < options >
2015-03-09 23:27:21 +03:00
* < name > , 0 x < addr > , < options >
* < name > , < options >
* < name >
*
* Only for the third form does the earlycon setup ( ) method receive the
* < options > string in the ' options ' parameter ; all other forms set
* the parameter to NULL .
*
* Returns 0 if an attempt to register the earlycon was made ,
* otherwise negative error code
*/
int __init setup_earlycon ( char * buf )
2015-03-09 23:27:20 +03:00
{
2015-03-09 23:27:21 +03:00
const struct earlycon_id * match ;
2015-03-09 23:27:20 +03:00
2015-03-09 23:27:21 +03:00
if ( ! buf | | ! buf [ 0 ] )
return - EINVAL ;
2015-03-09 23:27:20 +03:00
2015-03-09 23:27:21 +03:00
if ( early_con . flags & CON_ENABLED )
return - EALREADY ;
2015-03-09 23:27:20 +03:00
2015-03-09 23:27:21 +03:00
for ( match = __earlycon_table ; match - > name [ 0 ] ; match + + ) {
size_t len = strlen ( match - > name ) ;
2015-03-09 23:27:20 +03:00
2015-03-09 23:27:21 +03:00
if ( strncmp ( buf , match - > name , len ) )
continue ;
if ( buf [ len ] ) {
if ( buf [ len ] ! = ' , ' )
continue ;
buf + = len + 1 ;
} else
buf = NULL ;
return register_earlycon ( buf , match ) ;
}
return - ENOENT ;
}
/* early_param wrapper for setup_earlycon() */
static int __init param_setup_earlycon ( char * buf )
{
int err ;
/*
* Just ' earlycon ' is a valid param for devicetree earlycons ;
* don ' t generate a warning from parse_early_params ( ) in that case
*/
if ( ! buf | | ! buf [ 0 ] )
return 0 ;
err = setup_earlycon ( buf ) ;
2015-05-07 21:19:21 +03:00
if ( err = = - ENOENT | | err = = - EALREADY )
return 0 ;
2015-03-09 23:27:21 +03:00
return err ;
2015-03-09 23:27:20 +03:00
}
2015-03-09 23:27:21 +03:00
early_param ( " earlycon " , param_setup_earlycon ) ;
2015-03-09 23:27:20 +03:00
2014-03-27 17:06:16 +04:00
int __init of_setup_earlycon ( unsigned long addr ,
int ( * setup ) ( struct earlycon_device * , const char * ) )
{
int err ;
struct uart_port * port = & early_console_dev . port ;
port - > iotype = UPIO_MEM ;
port - > mapbase = addr ;
port - > uartclk = BASE_BAUD * 16 ;
port - > membase = earlycon_map ( addr , SZ_4K ) ;
early_console_dev . con - > data = & early_console_dev ;
err = setup ( & early_console_dev , NULL ) ;
if ( err < 0 )
return err ;
if ( ! early_console_dev . con - > write )
return - ENODEV ;
register_console ( early_console_dev . con ) ;
return 0 ;
}