2017-09-23 16:14:02 +02:00
/*
* Copyright ( c ) 2017 Martin Blumenstingl < martin . blumenstingl @ googlemail . com >
*
* SPDX - License - Identifier : GPL - 2.0 +
*/
# include <linux/io.h>
# include <linux/of.h>
# include <linux/of_address.h>
# include <linux/of_platform.h>
# include <linux/platform_device.h>
# include <linux/slab.h>
# include <linux/sys_soc.h>
# include <linux/bitfield.h>
# include <linux/regmap.h>
# include <linux/mfd/syscon.h>
# define MESON_SOCINFO_MAJOR_VER_MESON6 0x16
# define MESON_SOCINFO_MAJOR_VER_MESON8 0x19
# define MESON_SOCINFO_MAJOR_VER_MESON8B 0x1b
# define MESON_MX_ASSIST_HW_REV 0x14c
# define MESON_MX_ANALOG_TOP_METAL_REVISION 0x0
# define MESON_MX_BOOTROM_MISC_VER 0x4
static const char * meson_mx_socinfo_revision ( unsigned int major_ver ,
unsigned int misc_ver ,
unsigned int metal_rev )
{
unsigned int minor_ver ;
switch ( major_ver ) {
case MESON_SOCINFO_MAJOR_VER_MESON6 :
minor_ver = 0xa ;
break ;
case MESON_SOCINFO_MAJOR_VER_MESON8 :
if ( metal_rev = = 0x11111112 )
major_ver = 0x1d ;
if ( metal_rev = = 0x11111111 | | metal_rev = = 0x11111112 )
minor_ver = 0xa ;
else if ( metal_rev = = 0x11111113 )
minor_ver = 0xb ;
else if ( metal_rev = = 0x11111133 )
minor_ver = 0xc ;
else
minor_ver = 0xd ;
break ;
case MESON_SOCINFO_MAJOR_VER_MESON8B :
if ( metal_rev = = 0x11111111 )
minor_ver = 0xa ;
else
minor_ver = 0xb ;
break ;
default :
minor_ver = 0x0 ;
break ;
}
return kasprintf ( GFP_KERNEL , " Rev%X (%x - 0:%X) " , minor_ver , major_ver ,
misc_ver ) ;
}
static const char * meson_mx_socinfo_soc_id ( unsigned int major_ver ,
unsigned int metal_rev )
{
const char * soc_id ;
switch ( major_ver ) {
case MESON_SOCINFO_MAJOR_VER_MESON6 :
soc_id = " Meson6 (AML8726-MX) " ;
break ;
case MESON_SOCINFO_MAJOR_VER_MESON8 :
if ( metal_rev = = 0x11111112 )
soc_id = " Meson8m2 (S812) " ;
else
soc_id = " Meson8 (S802) " ;
break ;
case MESON_SOCINFO_MAJOR_VER_MESON8B :
soc_id = " Meson8b (S805) " ;
break ;
default :
soc_id = " Unknown " ;
break ;
}
return kstrdup_const ( soc_id , GFP_KERNEL ) ;
}
static const struct of_device_id meson_mx_socinfo_analog_top_ids [ ] = {
{ . compatible = " amlogic,meson8-analog-top " , } ,
{ . compatible = " amlogic,meson8b-analog-top " , } ,
{ /* sentinel */ }
} ;
2018-01-10 14:19:40 +00:00
static int __init meson_mx_socinfo_init ( void )
2017-09-23 16:14:02 +02:00
{
struct soc_device_attribute * soc_dev_attr ;
struct soc_device * soc_dev ;
struct device_node * np ;
struct regmap * assist_regmap , * bootrom_regmap , * analog_top_regmap ;
unsigned int major_ver , misc_ver , metal_rev = 0 ;
int ret ;
assist_regmap =
syscon_regmap_lookup_by_compatible ( " amlogic,meson-mx-assist " ) ;
if ( IS_ERR ( assist_regmap ) )
return PTR_ERR ( assist_regmap ) ;
bootrom_regmap =
syscon_regmap_lookup_by_compatible ( " amlogic,meson-mx-bootrom " ) ;
if ( IS_ERR ( bootrom_regmap ) )
return PTR_ERR ( bootrom_regmap ) ;
np = of_find_matching_node ( NULL , meson_mx_socinfo_analog_top_ids ) ;
if ( np ) {
analog_top_regmap = syscon_node_to_regmap ( np ) ;
if ( IS_ERR ( analog_top_regmap ) )
return PTR_ERR ( analog_top_regmap ) ;
ret = regmap_read ( analog_top_regmap ,
MESON_MX_ANALOG_TOP_METAL_REVISION ,
& metal_rev ) ;
if ( ret )
return ret ;
}
ret = regmap_read ( assist_regmap , MESON_MX_ASSIST_HW_REV , & major_ver ) ;
if ( ret < 0 )
return ret ;
ret = regmap_read ( bootrom_regmap , MESON_MX_BOOTROM_MISC_VER ,
& misc_ver ) ;
if ( ret < 0 )
return ret ;
soc_dev_attr = kzalloc ( sizeof ( * soc_dev_attr ) , GFP_KERNEL ) ;
if ( ! soc_dev_attr )
return - ENODEV ;
soc_dev_attr - > family = " Amlogic Meson " ;
np = of_find_node_by_path ( " / " ) ;
of_property_read_string ( np , " model " , & soc_dev_attr - > machine ) ;
of_node_put ( np ) ;
soc_dev_attr - > revision = meson_mx_socinfo_revision ( major_ver , misc_ver ,
metal_rev ) ;
soc_dev_attr - > soc_id = meson_mx_socinfo_soc_id ( major_ver , metal_rev ) ;
soc_dev = soc_device_register ( soc_dev_attr ) ;
if ( IS_ERR ( soc_dev ) ) {
kfree_const ( soc_dev_attr - > revision ) ;
kfree_const ( soc_dev_attr - > soc_id ) ;
kfree ( soc_dev_attr ) ;
return PTR_ERR ( soc_dev ) ;
}
dev_info ( soc_device_to_device ( soc_dev ) , " Amlogic %s %s detected \n " ,
soc_dev_attr - > soc_id , soc_dev_attr - > revision ) ;
return 0 ;
}
device_initcall ( meson_mx_socinfo_init ) ;