2005-11-23 09:56:06 +03:00
# include <linux/kernel.h>
# include <linux/serial.h>
# include <linux/serial_8250.h>
# include <linux/serial_core.h>
# include <linux/console.h>
# include <linux/pci.h>
2010-07-29 21:49:01 +04:00
# include <linux/of_address.h>
2008-01-24 19:59:12 +03:00
# include <linux/of_device.h>
2011-06-27 15:45:16 +04:00
# include <linux/serial_reg.h>
2005-11-23 09:56:06 +03:00
# include <asm/io.h>
# include <asm/mmu.h>
# include <asm/prom.h>
# include <asm/serial.h>
# include <asm/udbg.h>
# include <asm/pci-bridge.h>
# include <asm/ppc-pci.h>
# undef DEBUG
# ifdef DEBUG
# define DBG(fmt...) do { printk(fmt); } while(0)
# else
# define DBG(fmt...) do { } while(0)
# endif
# define MAX_LEGACY_SERIAL_PORTS 8
static struct plat_serial8250_port
legacy_serial_ports [ MAX_LEGACY_SERIAL_PORTS + 1 ] ;
static struct legacy_serial_info {
struct device_node * np ;
unsigned int speed ;
unsigned int clock ;
2006-07-03 15:36:01 +04:00
int irq_check_parent ;
2005-11-23 09:56:06 +03:00
phys_addr_t taddr ;
} legacy_serial_infos [ MAX_LEGACY_SERIAL_PORTS ] ;
2008-01-24 19:59:12 +03:00
2014-09-10 23:56:38 +04:00
static const struct of_device_id legacy_serial_parents [ ] __initconst = {
2008-01-24 19:59:12 +03:00
{ . type = " soc " , } ,
{ . type = " tsi-bridge " , } ,
2008-02-05 15:01:50 +03:00
{ . type = " opb " , } ,
{ . compatible = " ibm,opb " , } ,
2008-01-24 19:59:12 +03:00
{ . compatible = " simple-bus " , } ,
{ . compatible = " wrs,epld-localbus " , } ,
2008-07-07 10:39:50 +04:00
{ } ,
2008-01-24 19:59:12 +03:00
} ;
2005-11-23 09:56:06 +03:00
static unsigned int legacy_serial_count ;
static int legacy_serial_console = - 1 ;
2014-06-03 11:33:41 +04:00
static const upf_t legacy_port_flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST |
UPF_SHARE_IRQ | UPF_FIXED_PORT ;
2011-06-27 15:45:16 +04:00
static unsigned int tsi_serial_in ( struct uart_port * p , int offset )
{
unsigned int tmp ;
offset = offset < < p - > regshift ;
if ( offset = = UART_IIR ) {
tmp = readl ( p - > membase + ( UART_IIR & ~ 3 ) ) ;
return ( tmp > > 16 ) & 0xff ; /* UART_IIR % 4 == 2 */
} else
return readb ( p - > membase + offset ) ;
}
static void tsi_serial_out ( struct uart_port * p , int offset , int value )
{
offset = offset < < p - > regshift ;
if ( ! ( ( offset = = UART_IER ) & & ( value & UART_IER_UUE ) ) )
writeb ( value , p - > membase + offset ) ;
}
2005-11-23 09:56:06 +03:00
static int __init add_legacy_port ( struct device_node * np , int want_index ,
int iotype , phys_addr_t base ,
2005-12-21 01:16:52 +03:00
phys_addr_t taddr , unsigned long irq ,
2006-07-03 15:36:01 +04:00
upf_t flags , int irq_check_parent )
2005-11-23 09:56:06 +03:00
{
2014-04-20 03:43:10 +04:00
const __be32 * clk , * spd , * rs ;
2006-07-12 09:35:54 +04:00
u32 clock = BASE_BAUD * 16 ;
2014-04-20 03:43:10 +04:00
u32 shift = 0 ;
2005-11-23 09:56:06 +03:00
int index ;
/* get clock freq. if present */
2007-04-03 16:26:41 +04:00
clk = of_get_property ( np , " clock-frequency " , NULL ) ;
2005-11-24 20:08:56 +03:00
if ( clk & & * clk )
2010-10-01 11:06:07 +04:00
clock = be32_to_cpup ( clk ) ;
2005-11-23 09:56:06 +03:00
/* get default speed if present */
2007-04-03 16:26:41 +04:00
spd = of_get_property ( np , " current-speed " , NULL ) ;
2005-11-23 09:56:06 +03:00
2014-04-20 03:43:10 +04:00
/* get register shift if present */
rs = of_get_property ( np , " reg-shift " , NULL ) ;
if ( rs & & * rs )
shift = be32_to_cpup ( rs ) ;
2005-11-23 09:56:06 +03:00
/* If we have a location index, then try to use it */
if ( want_index > = 0 & & want_index < MAX_LEGACY_SERIAL_PORTS )
index = want_index ;
else
index = legacy_serial_count ;
/* if our index is still out of range, that mean that
* array is full , we could scan for a free slot but that
* make little sense to bother , just skip the port
*/
if ( index > = MAX_LEGACY_SERIAL_PORTS )
return - 1 ;
if ( index > = legacy_serial_count )
legacy_serial_count = index + 1 ;
/* Check if there is a port who already claimed our slot */
2013-08-06 20:01:24 +04:00
if ( legacy_serial_infos [ index ] . np ! = NULL ) {
2005-11-23 09:56:06 +03:00
/* if we still have some room, move it, else override */
if ( legacy_serial_count < MAX_LEGACY_SERIAL_PORTS ) {
2006-07-03 15:36:01 +04:00
printk ( KERN_DEBUG " Moved legacy port %d -> %d \n " ,
2005-11-23 09:56:06 +03:00
index , legacy_serial_count ) ;
legacy_serial_ports [ legacy_serial_count ] =
legacy_serial_ports [ index ] ;
legacy_serial_infos [ legacy_serial_count ] =
legacy_serial_infos [ index ] ;
legacy_serial_count + + ;
} else {
2006-07-03 15:36:01 +04:00
printk ( KERN_DEBUG " Replacing legacy port %d \n " , index ) ;
2005-11-23 09:56:06 +03:00
}
}
/* Now fill the entry */
memset ( & legacy_serial_ports [ index ] , 0 ,
sizeof ( struct plat_serial8250_port ) ) ;
if ( iotype = = UPIO_PORT )
legacy_serial_ports [ index ] . iobase = base ;
else
2005-11-29 03:21:59 +03:00
legacy_serial_ports [ index ] . mapbase = base ;
2011-06-27 15:45:16 +04:00
2005-11-23 09:56:06 +03:00
legacy_serial_ports [ index ] . iotype = iotype ;
legacy_serial_ports [ index ] . uartclk = clock ;
legacy_serial_ports [ index ] . irq = irq ;
2005-12-21 01:16:52 +03:00
legacy_serial_ports [ index ] . flags = flags ;
2014-04-20 03:43:10 +04:00
legacy_serial_ports [ index ] . regshift = shift ;
2005-11-23 09:56:06 +03:00
legacy_serial_infos [ index ] . taddr = taddr ;
legacy_serial_infos [ index ] . np = of_node_get ( np ) ;
legacy_serial_infos [ index ] . clock = clock ;
2010-10-01 11:06:07 +04:00
legacy_serial_infos [ index ] . speed = spd ? be32_to_cpup ( spd ) : 0 ;
2006-07-03 15:36:01 +04:00
legacy_serial_infos [ index ] . irq_check_parent = irq_check_parent ;
2005-11-23 09:56:06 +03:00
2011-06-27 15:45:16 +04:00
if ( iotype = = UPIO_TSI ) {
legacy_serial_ports [ index ] . serial_in = tsi_serial_in ;
legacy_serial_ports [ index ] . serial_out = tsi_serial_out ;
}
2006-07-03 15:36:01 +04:00
printk ( KERN_DEBUG " Found legacy serial port %d for %s \n " ,
2005-11-23 09:56:06 +03:00
index , np - > full_name ) ;
2006-07-03 15:36:01 +04:00
printk ( KERN_DEBUG " %s=%llx, taddr=%llx, irq=%lx, clk=%d, speed=%d \n " ,
2005-11-23 09:56:06 +03:00
( iotype = = UPIO_PORT ) ? " port " : " mem " ,
( unsigned long long ) base , ( unsigned long long ) taddr , irq ,
legacy_serial_ports [ index ] . uartclk ,
legacy_serial_infos [ index ] . speed ) ;
return index ;
}
2005-12-21 01:16:52 +03:00
static int __init add_legacy_soc_port ( struct device_node * np ,
struct device_node * soc_dev )
{
2006-07-04 08:14:07 +04:00
u64 addr ;
2013-08-06 20:01:43 +04:00
const __be32 * addrp ;
2006-08-23 06:20:27 +04:00
struct device_node * tsi = of_get_parent ( np ) ;
2005-12-21 01:16:52 +03:00
/* We only support ports that have a clock frequency properly
* encoded in the device - tree .
*/
2007-04-03 16:26:41 +04:00
if ( of_get_property ( np , " clock-frequency " , NULL ) = = NULL )
2005-12-21 01:16:52 +03:00
return - 1 ;
2014-04-20 03:43:10 +04:00
/* if reg-offset don't try to use it */
if ( ( of_get_property ( np , " reg-offset " , NULL ) ! = NULL ) )
2008-07-01 21:52:41 +04:00
return - 1 ;
2007-02-13 23:35:38 +03:00
/* if rtas uses this device, don't try to use it as well */
2007-04-03 16:26:41 +04:00
if ( of_get_property ( np , " used-by-rtas " , NULL ) ! = NULL )
2007-02-13 23:35:38 +03:00
return - 1 ;
2005-12-21 01:16:52 +03:00
/* Get the address */
addrp = of_get_address ( soc_dev , 0 , NULL , NULL ) ;
if ( addrp = = NULL )
return - 1 ;
addr = of_translate_address ( soc_dev , addrp ) ;
2006-07-03 11:24:15 +04:00
if ( addr = = OF_BAD_ADDR )
return - 1 ;
2005-12-21 01:16:52 +03:00
/* Add port, irq will be dealt with later. We passed a translated
* IO port value . It will be fixed up later along with the irq
*/
2006-08-23 06:20:27 +04:00
if ( tsi & & ! strcmp ( tsi - > type , " tsi-bridge " ) )
2014-06-03 11:33:41 +04:00
return add_legacy_port ( np , - 1 , UPIO_TSI , addr , addr ,
2016-09-06 14:53:24 +03:00
0 , legacy_port_flags , 0 ) ;
2006-08-23 06:20:27 +04:00
else
2014-06-03 11:33:41 +04:00
return add_legacy_port ( np , - 1 , UPIO_MEM , addr , addr ,
2016-09-06 14:53:24 +03:00
0 , legacy_port_flags , 0 ) ;
2005-12-21 01:16:52 +03:00
}
2005-11-23 09:56:06 +03:00
static int __init add_legacy_isa_port ( struct device_node * np ,
2006-01-04 01:15:21 +03:00
struct device_node * isa_brg )
2005-11-23 09:56:06 +03:00
{
2010-10-01 11:06:07 +04:00
const __be32 * reg ;
2006-07-12 09:35:54 +04:00
const char * typep ;
2005-11-23 09:56:06 +03:00
int index = - 1 ;
2006-07-04 08:14:07 +04:00
u64 taddr ;
2005-11-23 09:56:06 +03:00
2006-07-03 11:24:15 +04:00
DBG ( " -> add_legacy_isa_port(%s) \n " , np - > full_name ) ;
2005-11-23 09:56:06 +03:00
/* Get the ISA port number */
2007-04-03 16:26:41 +04:00
reg = of_get_property ( np , " reg " , NULL ) ;
2005-11-23 09:56:06 +03:00
if ( reg = = NULL )
return - 1 ;
/* Verify it's an IO port, we don't support anything else */
2010-10-01 11:06:07 +04:00
if ( ! ( be32_to_cpu ( reg [ 0 ] ) & 0x00000001 ) )
2005-11-23 09:56:06 +03:00
return - 1 ;
/* Now look for an "ibm,aix-loc" property that gives us ordering
* if any . . .
*/
2007-04-03 16:26:41 +04:00
typep = of_get_property ( np , " ibm,aix-loc " , NULL ) ;
2005-11-23 09:56:06 +03:00
/* If we have a location index, then use it */
if ( typep & & * typep = = ' S ' )
index = simple_strtol ( typep + 1 , NULL , 0 ) - 1 ;
2006-07-04 08:14:07 +04:00
/* Translate ISA address. If it fails, we still register the port
* with no translated address so that it can be picked up as an IO
* port later by the serial driver
2013-07-15 07:03:12 +04:00
*
* Note : Don ' t even try on P8 lpc , we know it ' s not directly mapped
2006-07-04 08:14:07 +04:00
*/
2017-01-30 10:11:57 +03:00
if ( ! of_device_is_compatible ( isa_brg , " ibm,power8-lpc " ) | |
of_get_property ( isa_brg , " ranges " , NULL ) ) {
2013-07-15 07:03:12 +04:00
taddr = of_translate_address ( np , reg ) ;
if ( taddr = = OF_BAD_ADDR )
taddr = 0 ;
} else
2006-07-04 08:14:07 +04:00
taddr = 0 ;
2005-11-23 09:56:06 +03:00
/* Add port, irq will be dealt with later */
2013-07-15 07:03:12 +04:00
return add_legacy_port ( np , index , UPIO_PORT , be32_to_cpu ( reg [ 1 ] ) ,
2016-09-06 14:53:24 +03:00
taddr , 0 , legacy_port_flags , 0 ) ;
2005-11-23 09:56:06 +03:00
}
2006-01-04 01:15:21 +03:00
# ifdef CONFIG_PCI
2005-11-23 09:56:06 +03:00
static int __init add_legacy_pci_port ( struct device_node * np ,
struct device_node * pci_dev )
{
2006-07-04 08:14:07 +04:00
u64 addr , base ;
2013-08-06 20:01:43 +04:00
const __be32 * addrp ;
2005-11-30 08:57:28 +03:00
unsigned int flags ;
2005-11-29 03:21:59 +03:00
int iotype , index = - 1 , lindex = 0 ;
2005-11-23 09:56:06 +03:00
2006-07-03 11:24:15 +04:00
DBG ( " -> add_legacy_pci_port(%s) \n " , np - > full_name ) ;
2005-11-23 09:56:06 +03:00
/* We only support ports that have a clock frequency properly
* encoded in the device - tree ( that is have an fcode ) . Anything
* else can ' t be used that early and will be normally probed by
2005-11-29 03:21:59 +03:00
* the generic 8250 _pci driver later on . The reason is that 8250
* compatible UARTs on PCI need all sort of quirks ( port offsets
* etc . . . ) that this code doesn ' t know about
2005-11-23 09:56:06 +03:00
*/
2007-04-03 16:26:41 +04:00
if ( of_get_property ( np , " clock-frequency " , NULL ) = = NULL )
2005-11-23 09:56:06 +03:00
return - 1 ;
/* Get the PCI address. Assume BAR 0 */
2005-11-30 08:57:28 +03:00
addrp = of_get_pci_address ( pci_dev , 0 , NULL , & flags ) ;
2005-11-23 09:56:06 +03:00
if ( addrp = = NULL )
return - 1 ;
/* We only support BAR 0 for now */
2005-11-30 08:57:28 +03:00
iotype = ( flags & IORESOURCE_MEM ) ? UPIO_MEM : UPIO_PORT ;
2005-11-23 09:56:06 +03:00
addr = of_translate_address ( pci_dev , addrp ) ;
2006-07-03 11:24:15 +04:00
if ( addr = = OF_BAD_ADDR )
return - 1 ;
2005-11-23 09:56:06 +03:00
/* Set the IO base to the same as the translated address for MMIO,
* or to the domain local IO base for PIO ( it will be fixed up later )
*/
if ( iotype = = UPIO_MEM )
base = addr ;
else
2013-08-06 20:01:43 +04:00
base = of_read_number ( & addrp [ 2 ] , 1 ) ;
2005-11-23 09:56:06 +03:00
/* Try to guess an index... If we have subdevices of the pci dev,
* we get to their " reg " property
*/
if ( np ! = pci_dev ) {
2010-10-01 11:06:07 +04:00
const __be32 * reg = of_get_property ( np , " reg " , NULL ) ;
if ( reg & & ( be32_to_cpup ( reg ) < 4 ) )
index = lindex = be32_to_cpup ( reg ) ;
2005-11-29 03:21:59 +03:00
}
/* Local index means it's the Nth port in the PCI chip. Unfortunately
* the offset to add here is device specific . We know about those
* EXAR ports and we default to the most common case . If your UART
* doesn ' t work for these settings , you ' ll have to add your own special
* cases here
*/
2007-05-03 11:26:52 +04:00
if ( of_device_is_compatible ( pci_dev , " pci13a8,152 " ) | |
of_device_is_compatible ( pci_dev , " pci13a8,154 " ) | |
of_device_is_compatible ( pci_dev , " pci13a8,158 " ) ) {
2005-11-29 03:21:59 +03:00
addr + = 0x200 * lindex ;
base + = 0x200 * lindex ;
} else {
addr + = 8 * lindex ;
base + = 8 * lindex ;
2005-11-23 09:56:06 +03:00
}
/* Add port, irq will be dealt with later. We passed a translated
* IO port value . It will be fixed up later along with the irq
*/
2016-09-06 14:53:24 +03:00
return add_legacy_port ( np , index , iotype , base , addr , 0 ,
2014-06-03 11:33:41 +04:00
legacy_port_flags , np ! = pci_dev ) ;
2005-11-23 09:56:06 +03:00
}
2006-01-04 01:15:21 +03:00
# endif
2005-11-23 09:56:06 +03:00
2006-03-26 04:07:35 +04:00
static void __init setup_legacy_serial_console ( int console )
{
2013-07-15 07:03:12 +04:00
struct legacy_serial_info * info = & legacy_serial_infos [ console ] ;
struct plat_serial8250_port * port = & legacy_serial_ports [ console ] ;
2006-03-26 04:07:35 +04:00
void __iomem * addr ;
2014-04-20 03:43:10 +04:00
unsigned int stride ;
stride = 1 < < port - > regshift ;
2006-03-26 04:07:35 +04:00
2013-07-15 07:03:12 +04:00
/* Check if a translated MMIO address has been found */
if ( info - > taddr ) {
addr = ioremap ( info - > taddr , 0x1000 ) ;
if ( addr = = NULL )
return ;
2014-04-20 03:43:10 +04:00
udbg_uart_init_mmio ( addr , stride ) ;
2013-07-15 07:03:12 +04:00
} else {
/* Check if it's PIO and we support untranslated PIO */
if ( port - > iotype = = UPIO_PORT & & isa_io_special )
2014-04-20 03:43:10 +04:00
udbg_uart_init_pio ( port - > iobase , stride ) ;
2013-07-15 07:03:12 +04:00
else
return ;
}
/* Try to query the current speed */
2006-03-26 04:07:35 +04:00
if ( info - > speed = = 0 )
2013-07-15 07:03:12 +04:00
info - > speed = udbg_probe_uart_speed ( info - > clock ) ;
/* Set it up */
2006-03-26 04:07:35 +04:00
DBG ( " default console speed = %d \n " , info - > speed ) ;
2013-07-15 07:03:12 +04:00
udbg_uart_setup ( info - > speed , info - > clock ) ;
2006-03-26 04:07:35 +04:00
}
2005-11-23 09:56:06 +03:00
/*
* This is called very early , as part of setup_system ( ) or eventually
* setup_arch ( ) , basically before anything else in this file . This function
* will try to build a list of all the available 8250 - compatible serial ports
* in the machine using the Open Firmware device - tree . It currently only deals
* with ISA and PCI busses but could be extended . It allows a very early boot
* console to be initialized , that list is also used later to provide 8250 with
* the machine non - PCI ports and to properly pick the default console port
*/
void __init find_legacy_serial_ports ( void )
{
2005-12-21 01:16:52 +03:00
struct device_node * np , * stdout = NULL ;
2006-07-12 09:35:54 +04:00
const char * path ;
2005-11-23 09:56:06 +03:00
int index ;
DBG ( " -> find_legacy_serial_port() \n " ) ;
/* Now find out if one of these is out firmware console */
2007-04-03 16:26:41 +04:00
path = of_get_property ( of_chosen , " linux,stdout-path " , NULL ) ;
2005-12-21 01:16:52 +03:00
if ( path ! = NULL ) {
stdout = of_find_node_by_path ( path ) ;
if ( stdout )
DBG ( " stdout is %s \n " , stdout - > full_name ) ;
} else {
2005-11-23 09:56:06 +03:00
DBG ( " no linux,stdout-path ! \n " ) ;
}
2005-12-21 01:16:52 +03:00
2008-01-24 19:59:12 +03:00
/* Iterate over all the 16550 ports, looking for known parents */
2007-11-29 22:45:47 +03:00
for_each_compatible_node ( np , " serial " , " ns16550 " ) {
2008-01-24 19:59:12 +03:00
struct device_node * parent = of_get_parent ( np ) ;
if ( ! parent )
continue ;
2008-07-07 10:39:50 +04:00
if ( of_match_node ( legacy_serial_parents , parent ) ! = NULL ) {
2011-04-06 11:26:29 +04:00
if ( of_device_is_available ( np ) ) {
index = add_legacy_soc_port ( np , np ) ;
if ( index > = 0 & & np = = stdout )
legacy_serial_console = index ;
}
2005-12-21 01:16:52 +03:00
}
2008-01-24 19:59:12 +03:00
of_node_put ( parent ) ;
2005-11-23 09:56:06 +03:00
}
2008-01-24 19:59:12 +03:00
/* Next, fill our array with ISA ports */
2007-11-29 22:45:47 +03:00
for_each_node_by_type ( np , " serial " ) {
2005-11-23 09:56:06 +03:00
struct device_node * isa = of_get_parent ( np ) ;
2013-07-15 07:03:12 +04:00
if ( isa & & ( ! strcmp ( isa - > name , " isa " ) | |
! strcmp ( isa - > name , " lpc " ) ) ) {
2013-07-15 07:03:13 +04:00
if ( of_device_is_available ( np ) ) {
index = add_legacy_isa_port ( np , isa ) ;
if ( index > = 0 & & np = = stdout )
legacy_serial_console = index ;
}
2005-11-23 09:56:06 +03:00
}
of_node_put ( isa ) ;
}
2006-01-04 01:15:21 +03:00
# ifdef CONFIG_PCI
2005-11-23 09:56:06 +03:00
/* Next, try to locate PCI ports */
for ( np = NULL ; ( np = of_find_all_nodes ( np ) ) ; ) {
struct device_node * pci , * parent = of_get_parent ( np ) ;
if ( parent & & ! strcmp ( parent - > name , " isa " ) ) {
of_node_put ( parent ) ;
continue ;
}
if ( strcmp ( np - > name , " serial " ) & & strcmp ( np - > type , " serial " ) ) {
of_node_put ( parent ) ;
continue ;
}
2012-09-20 05:48:00 +04:00
/* Check for known pciclass, and also check whether we have
2005-11-23 09:56:06 +03:00
* a device with child nodes for ports or not
*/
2007-05-03 11:26:52 +04:00
if ( of_device_is_compatible ( np , " pciclass,0700 " ) | |
of_device_is_compatible ( np , " pciclass,070002 " ) )
2005-11-23 09:56:06 +03:00
pci = np ;
2007-05-03 11:26:52 +04:00
else if ( of_device_is_compatible ( parent , " pciclass,0700 " ) | |
of_device_is_compatible ( parent , " pciclass,070002 " ) )
2005-11-23 09:56:06 +03:00
pci = parent ;
else {
of_node_put ( parent ) ;
continue ;
}
index = add_legacy_pci_port ( np , pci ) ;
if ( index > = 0 & & np = = stdout )
legacy_serial_console = index ;
of_node_put ( parent ) ;
}
2006-01-04 01:15:21 +03:00
# endif
2005-11-23 09:56:06 +03:00
DBG ( " legacy_serial_console = %d \n " , legacy_serial_console ) ;
2006-03-26 04:07:35 +04:00
if ( legacy_serial_console > = 0 )
setup_legacy_serial_console ( legacy_serial_console ) ;
2005-11-23 09:56:06 +03:00
DBG ( " <- find_legacy_serial_port() \n " ) ;
}
static struct platform_device serial_device = {
. name = " serial8250 " ,
. id = PLAT8250_DEV_PLATFORM ,
. dev = {
. platform_data = legacy_serial_ports ,
} ,
} ;
static void __init fixup_port_irq ( int index ,
struct device_node * np ,
struct plat_serial8250_port * port )
{
2006-07-03 15:36:01 +04:00
unsigned int virq ;
2005-11-23 09:56:06 +03:00
DBG ( " fixup_port_irq(%d) \n " , index ) ;
2006-07-03 15:36:01 +04:00
virq = irq_of_parse_and_map ( np , 0 ) ;
2016-09-06 14:53:24 +03:00
if ( ! virq & & legacy_serial_infos [ index ] . irq_check_parent ) {
2006-07-03 15:36:01 +04:00
np = of_get_parent ( np ) ;
if ( np = = NULL )
return ;
virq = irq_of_parse_and_map ( np , 0 ) ;
of_node_put ( np ) ;
2005-11-23 09:56:06 +03:00
}
2016-09-06 14:53:24 +03:00
if ( ! virq )
2005-11-23 09:56:06 +03:00
return ;
2006-07-03 15:36:01 +04:00
port - > irq = virq ;
2011-12-05 03:42:23 +04:00
2012-01-25 06:33:22 +04:00
# ifdef CONFIG_SERIAL_8250_FSL
2011-12-05 03:42:23 +04:00
if ( of_device_is_compatible ( np , " fsl,ns16550 " ) )
port - > handle_irq = fsl8250_handle_irq ;
2012-01-25 06:33:22 +04:00
# endif
2005-11-23 09:56:06 +03:00
}
static void __init fixup_port_pio ( int index ,
struct device_node * np ,
struct plat_serial8250_port * port )
{
2006-01-04 01:15:21 +03:00
# ifdef CONFIG_PCI
2005-11-23 09:56:06 +03:00
struct pci_controller * hose ;
DBG ( " fixup_port_pio(%d) \n " , index ) ;
hose = pci_find_hose_for_OF_device ( np ) ;
if ( hose ) {
unsigned long offset = ( unsigned long ) hose - > io_base_virt -
# ifdef CONFIG_PPC64
pci_io_base ;
# else
isa_io_base ;
# endif
DBG ( " port %d, IO %lx -> %lx \n " ,
index , port - > iobase , port - > iobase + offset ) ;
port - > iobase + = offset ;
}
2006-01-04 01:15:21 +03:00
# endif
2005-11-23 09:56:06 +03:00
}
2005-11-29 03:21:59 +03:00
static void __init fixup_port_mmio ( int index ,
struct device_node * np ,
struct plat_serial8250_port * port )
{
DBG ( " fixup_port_mmio(%d) \n " , index ) ;
port - > membase = ioremap ( port - > mapbase , 0x100 ) ;
}
2005-11-23 09:56:06 +03:00
/*
* This is called as an arch initcall , hopefully before the PCI bus is
* probed and / or the 8250 driver loaded since we need to register our
* platform devices before 8250 PCI ones are detected as some of them
* must properly " override " the platform ones .
*
* This function fixes up the interrupt value for platform ports as it
* couldn ' t be done earlier before interrupt maps have been parsed . It
* also " corrects " the IO address for PIO ports for the same reason ,
* since earlier , the PHBs virtual IO space wasn ' t assigned yet . It then
* registers all those platform ports for use by the 8250 driver when it
* finally loads .
*/
static int __init serial_dev_init ( void )
{
int i ;
if ( legacy_serial_count = = 0 )
return - ENODEV ;
/*
2010-01-07 02:03:52 +03:00
* Before we register the platform serial devices , we need
2007-12-17 22:30:12 +03:00
* to fixup their interrupts and their IO ports .
2005-11-23 09:56:06 +03:00
*/
DBG ( " Fixing serial ports interrupts and IO ports ... \n " ) ;
for ( i = 0 ; i < legacy_serial_count ; i + + ) {
struct plat_serial8250_port * port = & legacy_serial_ports [ i ] ;
struct device_node * np = legacy_serial_infos [ i ] . np ;
2016-09-06 14:53:24 +03:00
if ( ! port - > irq )
2005-11-23 09:56:06 +03:00
fixup_port_irq ( i , np , port ) ;
if ( port - > iotype = = UPIO_PORT )
fixup_port_pio ( i , np , port ) ;
2006-08-23 06:20:27 +04:00
if ( ( port - > iotype = = UPIO_MEM ) | | ( port - > iotype = = UPIO_TSI ) )
2005-11-29 03:21:59 +03:00
fixup_port_mmio ( i , np , port ) ;
2005-11-23 09:56:06 +03:00
}
DBG ( " Registering platform serial ports \n " ) ;
return platform_device_register ( & serial_device ) ;
}
2007-08-23 04:26:37 +04:00
device_initcall ( serial_dev_init ) ;
2005-11-23 09:56:06 +03:00
2008-07-28 07:49:15 +04:00
# ifdef CONFIG_SERIAL_8250_CONSOLE
2005-11-23 09:56:06 +03:00
/*
* This is called very early , as part of console_init ( ) ( typically just after
* time_init ( ) ) . This function is respondible for trying to find a good
* default console on serial ports . It tries to match the open firmware
2008-07-28 07:49:15 +04:00
* default output with one of the available serial console drivers that have
* been probed earlier by find_legacy_serial_ports ( )
2005-11-23 09:56:06 +03:00
*/
static int __init check_legacy_serial_console ( void )
{
struct device_node * prom_stdout = NULL ;
2008-07-28 07:49:15 +04:00
int i , speed = 0 , offset = 0 ;
2006-07-12 09:35:54 +04:00
const char * name ;
2010-10-01 11:06:07 +04:00
const __be32 * spd ;
2005-11-23 09:56:06 +03:00
DBG ( " -> check_legacy_serial_console() \n " ) ;
/* The user has requested a console so this is already set up. */
2007-02-12 11:54:17 +03:00
if ( strstr ( boot_command_line , " console= " ) ) {
2005-11-23 09:56:06 +03:00
DBG ( " console was specified ! \n " ) ;
return - EBUSY ;
}
if ( ! of_chosen ) {
DBG ( " of_chosen is NULL ! \n " ) ;
return - ENODEV ;
}
2005-12-21 01:16:52 +03:00
if ( legacy_serial_console < 0 ) {
DBG ( " legacy_serial_console not found ! \n " ) ;
return - ENODEV ;
}
2005-11-23 09:56:06 +03:00
/* We are getting a weird phandle from OF ... */
/* ... So use the full path instead */
2007-04-03 16:26:41 +04:00
name = of_get_property ( of_chosen , " linux,stdout-path " , NULL ) ;
2005-11-23 09:56:06 +03:00
if ( name = = NULL ) {
DBG ( " no linux,stdout-path ! \n " ) ;
return - ENODEV ;
}
prom_stdout = of_find_node_by_path ( name ) ;
if ( ! prom_stdout ) {
DBG ( " can't find stdout package %s ! \n " , name ) ;
return - ENODEV ;
}
DBG ( " stdout is %s \n " , prom_stdout - > full_name ) ;
2007-04-03 16:26:41 +04:00
name = of_get_property ( prom_stdout , " name " , NULL ) ;
2005-11-23 09:56:06 +03:00
if ( ! name ) {
DBG ( " stdout package has no name ! \n " ) ;
goto not_found ;
}
2007-04-03 16:26:41 +04:00
spd = of_get_property ( prom_stdout , " current-speed " , NULL ) ;
2005-11-23 09:56:06 +03:00
if ( spd )
2010-10-01 11:06:07 +04:00
speed = be32_to_cpup ( spd ) ;
2005-11-23 09:56:06 +03:00
2008-07-28 07:49:15 +04:00
if ( strcmp ( name , " serial " ) ! = 0 )
goto not_found ;
/* Look for it in probed array */
for ( i = 0 ; i < legacy_serial_count ; i + + ) {
if ( prom_stdout ! = legacy_serial_infos [ i ] . np )
continue ;
offset = i ;
speed = legacy_serial_infos [ i ] . speed ;
break ;
2005-11-23 09:56:06 +03:00
}
2008-07-28 07:49:15 +04:00
if ( i > = legacy_serial_count )
2005-11-23 09:56:06 +03:00
goto not_found ;
2008-07-28 07:49:15 +04:00
2005-11-23 09:56:06 +03:00
of_node_put ( prom_stdout ) ;
DBG ( " Found serial console at ttyS%d \n " , offset ) ;
if ( speed ) {
static char __initdata opt [ 16 ] ;
sprintf ( opt , " %d " , speed ) ;
return add_preferred_console ( " ttyS " , offset , opt ) ;
} else
return add_preferred_console ( " ttyS " , offset , NULL ) ;
not_found :
DBG ( " No preferred console found ! \n " ) ;
of_node_put ( prom_stdout ) ;
return - ENODEV ;
}
console_initcall ( check_legacy_serial_console ) ;
2008-07-28 07:49:15 +04:00
# endif /* CONFIG_SERIAL_8250_CONSOLE */