2012-06-01 18:21:46 +02:00
/*
2014-02-17 15:23:22 +01:00
* System controller support for Armada 370 , 375 and XP platforms .
2012-06-01 18:21:46 +02:00
*
* Copyright ( C ) 2012 Marvell
*
* Lior Amsalem < alior @ marvell . com >
* Gregory CLEMENT < gregory . clement @ free - electrons . com >
* Thomas Petazzoni < thomas . petazzoni @ 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 .
*
2014-02-17 15:23:22 +01:00
* The Armada 370 , 375 and Armada XP SoCs have a range of
2012-06-01 18:21:46 +02:00
* miscellaneous registers , that do not belong to a particular device ,
* but rather provide system - level features . This basic
* system - controller driver provides a device tree binding for those
* registers , and implements utility functions offering various
* features related to those registers .
*
* For now , the feature set is limited to restarting the platform by a
* soft - reset , but it might be extended in the future .
*/
# include <linux/kernel.h>
# include <linux/init.h>
# include <linux/of_address.h>
# include <linux/io.h>
2013-07-08 16:01:40 -07:00
# include <linux/reboot.h>
2013-11-07 17:02:38 +08:00
# include "common.h"
2014-07-23 15:00:41 +02:00
# include "mvebu-soc-id.h"
# include "pmsu.h"
# define ARMADA_375_CRYPT0_ENG_TARGET 41
# define ARMADA_375_CRYPT0_ENG_ATTR 1
2012-06-01 18:21:46 +02:00
static void __iomem * system_controller_base ;
2014-07-23 15:00:41 +02:00
static phys_addr_t system_controller_phys_base ;
2012-06-01 18:21:46 +02:00
struct mvebu_system_controller {
u32 rstoutn_mask_offset ;
u32 system_soft_reset_offset ;
u32 rstoutn_mask_reset_out_en ;
u32 system_soft_reset ;
2014-04-14 15:54:03 +02:00
u32 resume_boot_addr ;
2014-06-23 17:42:08 +02:00
u32 dev_id ;
u32 rev_id ;
2012-06-01 18:21:46 +02:00
} ;
static struct mvebu_system_controller * mvebu_sc ;
2013-11-07 17:02:38 +08:00
static const struct mvebu_system_controller armada_370_xp_system_controller = {
2012-06-01 18:21:46 +02:00
. rstoutn_mask_offset = 0x60 ,
. system_soft_reset_offset = 0x64 ,
. rstoutn_mask_reset_out_en = 0x1 ,
. system_soft_reset = 0x1 ,
2014-06-23 17:42:08 +02:00
. dev_id = 0x38 ,
. rev_id = 0x3c ,
2012-06-01 18:21:46 +02:00
} ;
2014-02-17 15:23:22 +01:00
static const struct mvebu_system_controller armada_375_system_controller = {
. rstoutn_mask_offset = 0x54 ,
. system_soft_reset_offset = 0x58 ,
. rstoutn_mask_reset_out_en = 0x1 ,
. system_soft_reset = 0x1 ,
2014-04-14 15:54:03 +02:00
. resume_boot_addr = 0xd4 ,
2014-06-23 17:42:08 +02:00
. dev_id = 0x38 ,
. rev_id = 0x3c ,
2014-02-17 15:23:22 +01:00
} ;
2013-11-07 17:02:38 +08:00
static const struct mvebu_system_controller orion_system_controller = {
2012-06-01 18:21:46 +02:00
. rstoutn_mask_offset = 0x108 ,
. system_soft_reset_offset = 0x10c ,
. rstoutn_mask_reset_out_en = 0x4 ,
. system_soft_reset = 0x1 ,
} ;
2014-02-11 10:24:02 -06:00
static const struct of_device_id of_system_controller_table [ ] = {
2012-06-01 18:21:46 +02:00
{
. compatible = " marvell,orion-system-controller " ,
. data = ( void * ) & orion_system_controller ,
} , {
. compatible = " marvell,armada-370-xp-system-controller " ,
. data = ( void * ) & armada_370_xp_system_controller ,
2014-02-17 15:23:22 +01:00
} , {
. compatible = " marvell,armada-375-system-controller " ,
. data = ( void * ) & armada_375_system_controller ,
2012-06-01 18:21:46 +02:00
} ,
{ /* end of list */ } ,
} ;
2013-07-08 16:01:40 -07:00
void mvebu_restart ( enum reboot_mode mode , const char * cmd )
2012-06-01 18:21:46 +02:00
{
if ( ! system_controller_base ) {
pr_err ( " Cannot restart, system-controller not available: check the device tree \n " ) ;
} else {
/*
* Enable soft reset to assert RSTOUTn .
*/
writel ( mvebu_sc - > rstoutn_mask_reset_out_en ,
system_controller_base +
mvebu_sc - > rstoutn_mask_offset ) ;
/*
* Assert soft reset .
*/
writel ( mvebu_sc - > system_soft_reset ,
system_controller_base +
mvebu_sc - > system_soft_reset_offset ) ;
}
while ( 1 )
;
}
2014-06-23 17:42:08 +02:00
int mvebu_system_controller_get_soc_id ( u32 * dev , u32 * rev )
{
if ( of_machine_is_compatible ( " marvell,armada380 " ) & &
system_controller_base ) {
* dev = readl ( system_controller_base + mvebu_sc - > dev_id ) > > 16 ;
* rev = ( readl ( system_controller_base + mvebu_sc - > rev_id ) > > 8 )
& 0xF ;
return 0 ;
} else
return - ENODEV ;
}
2015-02-02 15:27:16 +01:00
# if defined(CONFIG_SMP) && defined(CONFIG_MACH_MVEBU_V7)
2016-06-07 20:03:48 +01:00
static void mvebu_armada375_smp_wa_init ( void )
2014-07-23 15:00:41 +02:00
{
u32 dev , rev ;
phys_addr_t resume_addr_reg ;
if ( mvebu_get_soc_id ( & dev , & rev ) ! = 0 )
return ;
if ( rev ! = ARMADA_375_Z1_REV )
return ;
resume_addr_reg = system_controller_phys_base +
mvebu_sc - > resume_boot_addr ;
mvebu_setup_boot_addr_wa ( ARMADA_375_CRYPT0_ENG_TARGET ,
ARMADA_375_CRYPT0_ENG_ATTR ,
resume_addr_reg ) ;
}
2014-04-14 15:54:03 +02:00
void mvebu_system_controller_set_cpu_boot_addr ( void * boot_addr )
{
BUG_ON ( system_controller_base = = NULL ) ;
BUG_ON ( mvebu_sc - > resume_boot_addr = = 0 ) ;
2014-07-23 15:00:41 +02:00
if ( of_machine_is_compatible ( " marvell,armada375 " ) )
mvebu_armada375_smp_wa_init ( ) ;
2017-01-15 03:59:29 +01:00
writel ( __pa_symbol ( boot_addr ) , system_controller_base +
2014-04-14 15:54:03 +02:00
mvebu_sc - > resume_boot_addr ) ;
}
# endif
2012-06-01 18:21:46 +02:00
static int __init mvebu_system_controller_init ( void )
{
2014-02-11 10:24:02 -06:00
const struct of_device_id * match ;
2012-06-01 18:21:46 +02:00
struct device_node * np ;
2014-02-11 10:24:02 -06:00
np = of_find_matching_node_and_match ( NULL , of_system_controller_table ,
& match ) ;
2012-06-01 18:21:46 +02:00
if ( np ) {
2014-07-23 15:00:41 +02:00
struct resource res ;
2012-06-01 18:21:46 +02:00
system_controller_base = of_iomap ( np , 0 ) ;
2014-07-23 15:00:41 +02:00
of_address_to_resource ( np , 0 , & res ) ;
system_controller_phys_base = res . start ;
2012-06-01 18:21:46 +02:00
mvebu_sc = ( struct mvebu_system_controller * ) match - > data ;
2013-08-27 12:41:14 +08:00
of_node_put ( np ) ;
2012-06-01 18:21:46 +02:00
}
return 0 ;
}
2014-04-14 15:54:03 +02:00
early_initcall ( mvebu_system_controller_init ) ;