2017-02-16 13:31:06 +03:00
/*
* Copyright ( C ) 2015 Atmel
*
* Alexandre Belloni < alexandre . belloni @ free - electrons . com
* Boris Brezillon < boris . brezillon @ free - electrons . com
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed " as is " without any
* warranty of any kind , whether express or implied .
*
*/
# define pr_fmt(fmt) "AT91: " fmt
# include <linux/io.h>
# include <linux/of.h>
# include <linux/of_address.h>
# include <linux/of_platform.h>
# include <linux/slab.h>
# include <linux/sys_soc.h>
# include "soc.h"
# define AT91_DBGU_CIDR 0x40
# define AT91_DBGU_EXID 0x44
# define AT91_CHIPID_CIDR 0x00
# define AT91_CHIPID_EXID 0x04
# define AT91_CIDR_VERSION(x) ((x) & 0x1f)
# define AT91_CIDR_EXT BIT(31)
# define AT91_CIDR_MATCH_MASK 0x7fffffe0
static const struct at91_soc __initconst socs [ ] = {
# ifdef CONFIG_SOC_AT91RM9200
AT91_SOC ( AT91RM9200_CIDR_MATCH , 0 , " at91rm9200 BGA " , " at91rm9200 " ) ,
# endif
# ifdef CONFIG_SOC_AT91SAM9
AT91_SOC ( AT91SAM9260_CIDR_MATCH , 0 , " at91sam9260 " , NULL ) ,
AT91_SOC ( AT91SAM9261_CIDR_MATCH , 0 , " at91sam9261 " , NULL ) ,
AT91_SOC ( AT91SAM9263_CIDR_MATCH , 0 , " at91sam9263 " , NULL ) ,
AT91_SOC ( AT91SAM9G20_CIDR_MATCH , 0 , " at91sam9g20 " , NULL ) ,
AT91_SOC ( AT91SAM9RL64_CIDR_MATCH , 0 , " at91sam9rl64 " , NULL ) ,
AT91_SOC ( AT91SAM9G45_CIDR_MATCH , AT91SAM9M11_EXID_MATCH ,
" at91sam9m11 " , " at91sam9g45 " ) ,
AT91_SOC ( AT91SAM9G45_CIDR_MATCH , AT91SAM9M10_EXID_MATCH ,
" at91sam9m10 " , " at91sam9g45 " ) ,
AT91_SOC ( AT91SAM9G45_CIDR_MATCH , AT91SAM9G46_EXID_MATCH ,
" at91sam9g46 " , " at91sam9g45 " ) ,
AT91_SOC ( AT91SAM9G45_CIDR_MATCH , AT91SAM9G45_EXID_MATCH ,
" at91sam9g45 " , " at91sam9g45 " ) ,
AT91_SOC ( AT91SAM9X5_CIDR_MATCH , AT91SAM9G15_EXID_MATCH ,
" at91sam9g15 " , " at91sam9x5 " ) ,
AT91_SOC ( AT91SAM9X5_CIDR_MATCH , AT91SAM9G35_EXID_MATCH ,
" at91sam9g35 " , " at91sam9x5 " ) ,
AT91_SOC ( AT91SAM9X5_CIDR_MATCH , AT91SAM9X35_EXID_MATCH ,
" at91sam9x35 " , " at91sam9x5 " ) ,
AT91_SOC ( AT91SAM9X5_CIDR_MATCH , AT91SAM9G25_EXID_MATCH ,
" at91sam9g25 " , " at91sam9x5 " ) ,
AT91_SOC ( AT91SAM9X5_CIDR_MATCH , AT91SAM9X25_EXID_MATCH ,
" at91sam9x25 " , " at91sam9x5 " ) ,
AT91_SOC ( AT91SAM9N12_CIDR_MATCH , AT91SAM9CN12_EXID_MATCH ,
" at91sam9cn12 " , " at91sam9n12 " ) ,
AT91_SOC ( AT91SAM9N12_CIDR_MATCH , AT91SAM9N12_EXID_MATCH ,
" at91sam9n12 " , " at91sam9n12 " ) ,
AT91_SOC ( AT91SAM9N12_CIDR_MATCH , AT91SAM9CN11_EXID_MATCH ,
" at91sam9cn11 " , " at91sam9n12 " ) ,
AT91_SOC ( AT91SAM9XE128_CIDR_MATCH , 0 , " at91sam9xe128 " , " at91sam9xe128 " ) ,
AT91_SOC ( AT91SAM9XE256_CIDR_MATCH , 0 , " at91sam9xe256 " , " at91sam9xe256 " ) ,
AT91_SOC ( AT91SAM9XE512_CIDR_MATCH , 0 , " at91sam9xe512 " , " at91sam9xe512 " ) ,
2019-11-29 16:51:40 +03:00
# endif
# ifdef CONFIG_SOC_SAM9X60
AT91_SOC ( SAM9X60_CIDR_MATCH , SAM9X60_EXID_MATCH , " sam9x60 " , " sam9x60 " ) ,
2020-10-08 15:50:28 +03:00
AT91_SOC ( SAM9X60_CIDR_MATCH , SAM9X60_D5M_EXID_MATCH ,
" sam9x60 64MiB DDR2 SiP " , " sam9x60 " ) ,
AT91_SOC ( SAM9X60_CIDR_MATCH , SAM9X60_D1G_EXID_MATCH ,
" sam9x60 128MiB DDR2 SiP " , " sam9x60 " ) ,
AT91_SOC ( SAM9X60_CIDR_MATCH , SAM9X60_D6K_EXID_MATCH ,
" sam9x60 8MiB SDRAM SiP " , " sam9x60 " ) ,
2017-02-16 13:31:06 +03:00
# endif
# ifdef CONFIG_SOC_SAMA5
AT91_SOC ( SAMA5D2_CIDR_MATCH , SAMA5D21CU_EXID_MATCH ,
" sama5d21 " , " sama5d2 " ) ,
AT91_SOC ( SAMA5D2_CIDR_MATCH , SAMA5D22CU_EXID_MATCH ,
" sama5d22 " , " sama5d2 " ) ,
2017-07-06 11:35:27 +03:00
AT91_SOC ( SAMA5D2_CIDR_MATCH , SAMA5D225C_D1M_EXID_MATCH ,
" sama5d225c 16MiB SiP " , " sama5d2 " ) ,
2017-02-16 13:31:06 +03:00
AT91_SOC ( SAMA5D2_CIDR_MATCH , SAMA5D23CU_EXID_MATCH ,
" sama5d23 " , " sama5d2 " ) ,
AT91_SOC ( SAMA5D2_CIDR_MATCH , SAMA5D24CX_EXID_MATCH ,
" sama5d24 " , " sama5d2 " ) ,
AT91_SOC ( SAMA5D2_CIDR_MATCH , SAMA5D24CU_EXID_MATCH ,
" sama5d24 " , " sama5d2 " ) ,
AT91_SOC ( SAMA5D2_CIDR_MATCH , SAMA5D26CU_EXID_MATCH ,
" sama5d26 " , " sama5d2 " ) ,
AT91_SOC ( SAMA5D2_CIDR_MATCH , SAMA5D27CU_EXID_MATCH ,
" sama5d27 " , " sama5d2 " ) ,
AT91_SOC ( SAMA5D2_CIDR_MATCH , SAMA5D27CN_EXID_MATCH ,
" sama5d27 " , " sama5d2 " ) ,
2017-07-06 11:35:27 +03:00
AT91_SOC ( SAMA5D2_CIDR_MATCH , SAMA5D27C_D1G_EXID_MATCH ,
" sama5d27c 128MiB SiP " , " sama5d2 " ) ,
AT91_SOC ( SAMA5D2_CIDR_MATCH , SAMA5D27C_D5M_EXID_MATCH ,
" sama5d27c 64MiB SiP " , " sama5d2 " ) ,
2018-11-28 14:00:35 +03:00
AT91_SOC ( SAMA5D2_CIDR_MATCH , SAMA5D27C_LD1G_EXID_MATCH ,
" sama5d27c 128MiB LPDDR2 SiP " , " sama5d2 " ) ,
AT91_SOC ( SAMA5D2_CIDR_MATCH , SAMA5D27C_LD2G_EXID_MATCH ,
" sama5d27c 256MiB LPDDR2 SiP " , " sama5d2 " ) ,
2017-02-16 13:31:06 +03:00
AT91_SOC ( SAMA5D2_CIDR_MATCH , SAMA5D28CU_EXID_MATCH ,
" sama5d28 " , " sama5d2 " ) ,
AT91_SOC ( SAMA5D2_CIDR_MATCH , SAMA5D28CN_EXID_MATCH ,
" sama5d28 " , " sama5d2 " ) ,
2017-07-06 11:35:27 +03:00
AT91_SOC ( SAMA5D2_CIDR_MATCH , SAMA5D28C_D1G_EXID_MATCH ,
" sama5d28c 128MiB SiP " , " sama5d2 " ) ,
2018-11-28 14:00:35 +03:00
AT91_SOC ( SAMA5D2_CIDR_MATCH , SAMA5D28C_LD1G_EXID_MATCH ,
" sama5d28c 128MiB LPDDR2 SiP " , " sama5d2 " ) ,
AT91_SOC ( SAMA5D2_CIDR_MATCH , SAMA5D28C_LD2G_EXID_MATCH ,
" sama5d28c 256MiB LPDDR2 SiP " , " sama5d2 " ) ,
2017-02-16 13:31:06 +03:00
AT91_SOC ( SAMA5D3_CIDR_MATCH , SAMA5D31_EXID_MATCH ,
" sama5d31 " , " sama5d3 " ) ,
AT91_SOC ( SAMA5D3_CIDR_MATCH , SAMA5D33_EXID_MATCH ,
" sama5d33 " , " sama5d3 " ) ,
AT91_SOC ( SAMA5D3_CIDR_MATCH , SAMA5D34_EXID_MATCH ,
" sama5d34 " , " sama5d3 " ) ,
AT91_SOC ( SAMA5D3_CIDR_MATCH , SAMA5D35_EXID_MATCH ,
" sama5d35 " , " sama5d3 " ) ,
AT91_SOC ( SAMA5D3_CIDR_MATCH , SAMA5D36_EXID_MATCH ,
" sama5d36 " , " sama5d3 " ) ,
AT91_SOC ( SAMA5D4_CIDR_MATCH , SAMA5D41_EXID_MATCH ,
" sama5d41 " , " sama5d4 " ) ,
AT91_SOC ( SAMA5D4_CIDR_MATCH , SAMA5D42_EXID_MATCH ,
" sama5d42 " , " sama5d4 " ) ,
AT91_SOC ( SAMA5D4_CIDR_MATCH , SAMA5D43_EXID_MATCH ,
" sama5d43 " , " sama5d4 " ) ,
AT91_SOC ( SAMA5D4_CIDR_MATCH , SAMA5D44_EXID_MATCH ,
" sama5d44 " , " sama5d4 " ) ,
2017-05-31 04:06:23 +03:00
# endif
# ifdef CONFIG_SOC_SAMV7
AT91_SOC ( SAME70Q21_CIDR_MATCH , SAME70Q21_EXID_MATCH ,
" same70q21 " , " same7 " ) ,
AT91_SOC ( SAME70Q20_CIDR_MATCH , SAME70Q20_EXID_MATCH ,
" same70q20 " , " same7 " ) ,
AT91_SOC ( SAME70Q19_CIDR_MATCH , SAME70Q19_EXID_MATCH ,
" same70q19 " , " same7 " ) ,
AT91_SOC ( SAMS70Q21_CIDR_MATCH , SAMS70Q21_EXID_MATCH ,
" sams70q21 " , " sams7 " ) ,
AT91_SOC ( SAMS70Q20_CIDR_MATCH , SAMS70Q20_EXID_MATCH ,
" sams70q20 " , " sams7 " ) ,
AT91_SOC ( SAMS70Q19_CIDR_MATCH , SAMS70Q19_EXID_MATCH ,
" sams70q19 " , " sams7 " ) ,
AT91_SOC ( SAMV71Q21_CIDR_MATCH , SAMV71Q21_EXID_MATCH ,
" samv71q21 " , " samv7 " ) ,
AT91_SOC ( SAMV71Q20_CIDR_MATCH , SAMV71Q20_EXID_MATCH ,
" samv71q20 " , " samv7 " ) ,
AT91_SOC ( SAMV71Q19_CIDR_MATCH , SAMV71Q19_EXID_MATCH ,
" samv71q19 " , " samv7 " ) ,
AT91_SOC ( SAMV70Q20_CIDR_MATCH , SAMV70Q20_EXID_MATCH ,
" samv70q20 " , " samv7 " ) ,
AT91_SOC ( SAMV70Q19_CIDR_MATCH , SAMV70Q19_EXID_MATCH ,
" samv70q19 " , " samv7 " ) ,
2017-02-16 13:31:06 +03:00
# endif
{ /* sentinel */ } ,
} ;
static int __init at91_get_cidr_exid_from_dbgu ( u32 * cidr , u32 * exid )
{
struct device_node * np ;
void __iomem * regs ;
np = of_find_compatible_node ( NULL , NULL , " atmel,at91rm9200-dbgu " ) ;
if ( ! np )
np = of_find_compatible_node ( NULL , NULL ,
" atmel,at91sam9260-dbgu " ) ;
if ( ! np )
return - ENODEV ;
regs = of_iomap ( np , 0 ) ;
of_node_put ( np ) ;
if ( ! regs ) {
pr_warn ( " Could not map DBGU iomem range " ) ;
return - ENXIO ;
}
* cidr = readl ( regs + AT91_DBGU_CIDR ) ;
* exid = readl ( regs + AT91_DBGU_EXID ) ;
iounmap ( regs ) ;
return 0 ;
}
static int __init at91_get_cidr_exid_from_chipid ( u32 * cidr , u32 * exid )
{
struct device_node * np ;
void __iomem * regs ;
np = of_find_compatible_node ( NULL , NULL , " atmel,sama5d2-chipid " ) ;
if ( ! np )
return - ENODEV ;
regs = of_iomap ( np , 0 ) ;
of_node_put ( np ) ;
if ( ! regs ) {
pr_warn ( " Could not map DBGU iomem range " ) ;
return - ENXIO ;
}
* cidr = readl ( regs + AT91_CHIPID_CIDR ) ;
* exid = readl ( regs + AT91_CHIPID_EXID ) ;
iounmap ( regs ) ;
return 0 ;
}
struct soc_device * __init at91_soc_init ( const struct at91_soc * socs )
{
struct soc_device_attribute * soc_dev_attr ;
const struct at91_soc * soc ;
struct soc_device * soc_dev ;
u32 cidr , exid ;
int ret ;
/*
* With SAMA5D2 and later SoCs , CIDR and EXID registers are no more
* in the dbgu device but in the chipid device whose purpose is only
* to expose these two registers .
*/
ret = at91_get_cidr_exid_from_dbgu ( & cidr , & exid ) ;
if ( ret )
ret = at91_get_cidr_exid_from_chipid ( & cidr , & exid ) ;
if ( ret ) {
if ( ret = = - ENODEV )
pr_warn ( " Could not find identification node " ) ;
return NULL ;
}
for ( soc = socs ; soc - > name ; soc + + ) {
if ( soc - > cidr_match ! = ( cidr & AT91_CIDR_MATCH_MASK ) )
continue ;
if ( ! ( cidr & AT91_CIDR_EXT ) | | soc - > exid_match = = exid )
break ;
}
if ( ! soc - > name ) {
pr_warn ( " Could not find matching SoC description \n " ) ;
return NULL ;
}
soc_dev_attr = kzalloc ( sizeof ( * soc_dev_attr ) , GFP_KERNEL ) ;
if ( ! soc_dev_attr )
return NULL ;
soc_dev_attr - > family = soc - > family ;
soc_dev_attr - > soc_id = soc - > name ;
soc_dev_attr - > revision = kasprintf ( GFP_KERNEL , " %X " ,
AT91_CIDR_VERSION ( cidr ) ) ;
soc_dev = soc_device_register ( soc_dev_attr ) ;
if ( IS_ERR ( soc_dev ) ) {
kfree ( soc_dev_attr - > revision ) ;
kfree ( soc_dev_attr ) ;
pr_warn ( " Could not register SoC device \n " ) ;
return NULL ;
}
if ( soc - > family )
pr_info ( " Detected SoC family: %s \n " , soc - > family ) ;
pr_info ( " Detected SoC: %s, revision %X \n " , soc - > name ,
AT91_CIDR_VERSION ( cidr ) ) ;
return soc_dev ;
}
2020-12-11 16:58:46 +03:00
static const struct of_device_id at91_soc_allowed_list [ ] __initconst = {
{ . compatible = " atmel,at91rm9200 " , } ,
{ . compatible = " atmel,at91sam9 " , } ,
{ . compatible = " atmel,sama5 " , } ,
{ . compatible = " atmel,samv7 " , }
} ;
2017-02-16 13:31:06 +03:00
static int __init atmel_soc_device_init ( void )
{
2020-12-11 16:58:46 +03:00
struct device_node * np = of_find_node_by_path ( " / " ) ;
if ( ! of_match_node ( at91_soc_allowed_list , np ) )
return 0 ;
2017-02-16 13:31:06 +03:00
at91_soc_init ( socs ) ;
return 0 ;
}
subsys_initcall ( atmel_soc_device_init ) ;