2016-09-27 23:54:13 +03:00
/*
* Copyright ( c ) 2012 , Intel Corporation
* Copyright ( c ) 2015 , Red Hat , Inc .
* Copyright ( c ) 2015 , 2016 Linaro Ltd .
*
* 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 .
*
*/
# define pr_fmt(fmt) "ACPI: SPCR: " fmt
# include <linux/acpi.h>
# include <linux/console.h>
# include <linux/kernel.h>
# include <linux/serial_core.h>
2017-07-28 00:15:52 +03:00
/*
* Erratum 44 for QDF2432v1 and QDF2400v1 SoCs describes the BUSY bit as
* occasionally getting stuck as 1. To avoid the potential for a hang , check
* TXFE = = 0 instead of BUSY = = 1. This may not be suitable for all UART
* implementations , so only do so if an affected platform is detected in
2018-01-18 18:09:51 +03:00
* acpi_parse_spcr ( ) .
2017-07-28 00:15:52 +03:00
*/
bool qdf2400_e44_present ;
EXPORT_SYMBOL ( qdf2400_e44_present ) ;
2017-02-16 00:39:43 +03:00
/*
* Some Qualcomm Datacenter Technologies SoCs have a defective UART BUSY bit .
* Detect them by examining the OEM fields in the SPCR header , similiar to PCI
* quirk detection in pci_mcfg . c .
*/
static bool qdf2400_erratum_44_present ( struct acpi_table_header * h )
{
if ( memcmp ( h - > oem_id , " QCOM " , ACPI_OEM_ID_SIZE ) )
return false ;
if ( ! memcmp ( h - > oem_table_id , " QDF2432 " , ACPI_OEM_TABLE_ID_SIZE ) )
return true ;
if ( ! memcmp ( h - > oem_table_id , " QDF2400 " , ACPI_OEM_TABLE_ID_SIZE ) & &
2017-02-28 23:30:33 +03:00
h - > oem_revision = = 1 )
2017-02-16 00:39:43 +03:00
return true ;
return false ;
}
2017-07-04 00:33:09 +03:00
/*
* APM X - Gene v1 and v2 UART hardware is an 16550 like device but has its
* register aligned to 32 - bit . In addition , the BIOS also encoded the
* access width to be 8 bits . This function detects this errata condition .
*/
static bool xgene_8250_erratum_present ( struct acpi_table_spcr * tb )
{
2017-08-05 00:49:43 +03:00
bool xgene_8250 = false ;
2017-07-04 00:33:09 +03:00
if ( tb - > interface_type ! = ACPI_DBG2_16550_COMPATIBLE )
return false ;
2017-08-05 00:49:43 +03:00
if ( memcmp ( tb - > header . oem_id , " APMC0D " , ACPI_OEM_ID_SIZE ) & &
memcmp ( tb - > header . oem_id , " HPE " , ACPI_OEM_ID_SIZE ) )
2017-07-04 00:33:09 +03:00
return false ;
if ( ! memcmp ( tb - > header . oem_table_id , " XGENESPC " ,
ACPI_OEM_TABLE_ID_SIZE ) & & tb - > header . oem_revision = = 0 )
2017-08-05 00:49:43 +03:00
xgene_8250 = true ;
2017-07-04 00:33:09 +03:00
2017-08-05 00:49:43 +03:00
if ( ! memcmp ( tb - > header . oem_table_id , " ProLiant " ,
ACPI_OEM_TABLE_ID_SIZE ) & & tb - > header . oem_revision = = 1 )
xgene_8250 = true ;
return xgene_8250 ;
2017-07-04 00:33:09 +03:00
}
2016-09-27 23:54:13 +03:00
/**
2018-01-18 18:09:51 +03:00
* acpi_parse_spcr ( ) - parse ACPI SPCR table and add preferred console
2016-09-27 23:54:13 +03:00
*
2018-01-18 18:09:51 +03:00
* @ enable_earlycon : set up earlycon for the console specified by the table
* @ enable_console : setup the console specified by the table .
2016-09-27 23:54:13 +03:00
*
* For the architectures with support for ACPI , CONFIG_ACPI_SPCR_TABLE may be
* defined to parse ACPI SPCR table . As a result of the parsing preferred
2018-01-18 18:09:51 +03:00
* console is registered and if @ enable_earlycon is true , earlycon is set up .
* If @ enable_console is true the system console is also configured .
2016-09-27 23:54:13 +03:00
*
* When CONFIG_ACPI_SPCR_TABLE is defined , this function should be called
2017-02-28 01:29:20 +03:00
* from arch initialization code as soon as the DT / ACPI decision is made .
2016-09-27 23:54:13 +03:00
*
*/
2018-01-18 18:09:51 +03:00
int __init acpi_parse_spcr ( bool enable_earlycon , bool enable_console )
2016-09-27 23:54:13 +03:00
{
static char opts [ 64 ] ;
struct acpi_table_spcr * table ;
acpi_status status ;
char * uart ;
char * iotype ;
int baud_rate ;
int err ;
if ( acpi_disabled )
return - ENODEV ;
2016-12-14 10:04:39 +03:00
status = acpi_get_table ( ACPI_SIG_SPCR , 0 ,
( struct acpi_table_header * * ) & table ) ;
2016-09-27 23:54:13 +03:00
if ( ACPI_FAILURE ( status ) )
return - ENOENT ;
2018-01-18 18:09:51 +03:00
if ( table - > header . revision < 2 )
pr_info ( " SPCR table version %d \n " , table - > header . revision ) ;
2016-09-27 23:54:13 +03:00
2017-07-04 00:33:08 +03:00
if ( table - > serial_port . space_id = = ACPI_ADR_SPACE_SYSTEM_MEMORY ) {
2017-08-03 09:26:19 +03:00
switch ( ACPI_ACCESS_BIT_WIDTH ( (
table - > serial_port . access_width ) ) ) {
2017-07-04 00:33:08 +03:00
default :
pr_err ( " Unexpected SPCR Access Width. Defaulting to byte size \n " ) ;
2018-02-09 21:08:21 +03:00
/* fall through */
2017-08-03 09:26:19 +03:00
case 8 :
2017-07-04 00:33:08 +03:00
iotype = " mmio " ;
break ;
2017-08-03 09:26:19 +03:00
case 16 :
2017-07-04 00:33:08 +03:00
iotype = " mmio16 " ;
break ;
2017-08-03 09:26:19 +03:00
case 32 :
2017-07-04 00:33:08 +03:00
iotype = " mmio32 " ;
break ;
}
} else
iotype = " io " ;
2016-09-27 23:54:13 +03:00
switch ( table - > interface_type ) {
case ACPI_DBG2_ARM_SBSA_32BIT :
iotype = " mmio32 " ;
/* fall through */
case ACPI_DBG2_ARM_PL011 :
case ACPI_DBG2_ARM_SBSA_GENERIC :
case ACPI_DBG2_BCM2835 :
uart = " pl011 " ;
break ;
case ACPI_DBG2_16550_COMPATIBLE :
case ACPI_DBG2_16550_SUBSET :
uart = " uart " ;
break ;
default :
err = - ENOENT ;
goto done ;
}
switch ( table - > baud_rate ) {
case 3 :
baud_rate = 9600 ;
break ;
case 4 :
baud_rate = 19200 ;
break ;
case 6 :
baud_rate = 57600 ;
break ;
case 7 :
baud_rate = 115200 ;
break ;
default :
err = - ENOENT ;
goto done ;
}
2017-07-28 00:15:52 +03:00
/*
* If the E44 erratum is required , then we need to tell the pl011
* driver to implement the work - around .
*
* The global variable is used by the probe function when it
* creates the UARTs , whether or not they ' re used as a console .
*
* If the user specifies " traditional " earlycon , the qdf2400_e44
* console name matches the EARLYCON_DECLARE ( ) statement , and
* SPCR is not used . Parameter " earlycon " is false .
*
* If the user specifies " SPCR " earlycon , then we need to update
* the console name so that it also says " qdf2400_e44 " . Parameter
* " earlycon " is true .
*
* For consistency , if we change the console name , then we do it
* for everyone , not just earlycon .
*/
if ( qdf2400_erratum_44_present ( & table - > header ) ) {
qdf2400_e44_present = true ;
2018-01-18 18:09:51 +03:00
if ( enable_earlycon )
2017-07-28 00:15:52 +03:00
uart = " qdf2400_e44 " ;
}
2017-08-05 00:49:44 +03:00
if ( xgene_8250_erratum_present ( table ) ) {
2017-07-04 00:33:09 +03:00
iotype = " mmio32 " ;
2017-02-16 00:39:43 +03:00
2017-08-05 00:49:44 +03:00
/* for xgene v1 and v2 we don't know the clock rate of the
* UART so don ' t attempt to change to the baud rate state
* in the table because driver cannot calculate the dividers
*/
snprintf ( opts , sizeof ( opts ) , " %s,%s,0x%llx " , uart , iotype ,
table - > serial_port . address ) ;
} else {
snprintf ( opts , sizeof ( opts ) , " %s,%s,0x%llx,%d " , uart , iotype ,
table - > serial_port . address , baud_rate ) ;
}
2016-09-27 23:54:13 +03:00
pr_info ( " console: %s \n " , opts ) ;
2018-01-18 18:09:51 +03:00
if ( enable_earlycon )
2016-09-27 23:54:13 +03:00
setup_earlycon ( opts ) ;
2018-01-18 18:09:51 +03:00
if ( enable_console )
err = add_preferred_console ( uart , 0 , opts + strlen ( uart ) + 1 ) ;
else
err = 0 ;
2016-09-27 23:54:13 +03:00
done :
2016-12-14 10:04:39 +03:00
acpi_put_table ( ( struct acpi_table_header * ) table ) ;
2016-09-27 23:54:13 +03:00
return err ;
}