2018-01-16 11:12:35 +01:00
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/*
* Microsemi MIPS SoC reset driver
*
* License : Dual MIT / GPL
* Copyright ( c ) 2017 Microsemi Corporation
*/
# include <linux/delay.h>
# include <linux/io.h>
# include <linux/notifier.h>
# include <linux/mfd/syscon.h>
# include <linux/of_address.h>
# include <linux/of_device.h>
# include <linux/platform_device.h>
# include <linux/reboot.h>
# include <linux/regmap.h>
2020-10-06 22:03:15 +02:00
struct reset_props {
const char * syscon ;
u32 protect_reg ;
u32 vcore_protect ;
u32 if_si_owner_bit ;
} ;
2018-01-16 11:12:35 +01:00
struct ocelot_reset_context {
void __iomem * base ;
struct regmap * cpu_ctrl ;
2020-10-06 22:03:15 +02:00
const struct reset_props * props ;
2018-01-16 11:12:35 +01:00
struct notifier_block restart_handler ;
} ;
2020-11-25 08:19:19 +01:00
# define BIT_OFF_INVALID 32
2018-01-16 11:12:35 +01:00
# define SOFT_CHIP_RST BIT(0)
2018-11-09 20:57:00 +01:00
# define ICPU_CFG_CPU_SYSTEM_CTRL_GENERAL_CTRL 0x24
# define IF_SI_OWNER_MASK GENMASK(1, 0)
# define IF_SI_OWNER_SISL 0
# define IF_SI_OWNER_SIBM 1
# define IF_SI_OWNER_SIMC 2
2018-01-16 11:12:35 +01:00
static int ocelot_restart_handle ( struct notifier_block * this ,
unsigned long mode , void * cmd )
{
struct ocelot_reset_context * ctx = container_of ( this , struct
ocelot_reset_context ,
restart_handler ) ;
2020-10-06 22:03:15 +02:00
u32 if_si_owner_bit = ctx - > props - > if_si_owner_bit ;
2018-01-16 11:12:35 +01:00
/* Make sure the core is not protected from reset */
2020-10-06 22:03:15 +02:00
regmap_update_bits ( ctx - > cpu_ctrl , ctx - > props - > protect_reg ,
ctx - > props - > vcore_protect , 0 ) ;
2018-01-16 11:12:35 +01:00
2018-11-09 20:57:00 +01:00
/* Make the SI back to boot mode */
2020-11-25 08:19:19 +01:00
if ( if_si_owner_bit ! = BIT_OFF_INVALID )
regmap_update_bits ( ctx - > cpu_ctrl ,
ICPU_CFG_CPU_SYSTEM_CTRL_GENERAL_CTRL ,
IF_SI_OWNER_MASK < < if_si_owner_bit ,
IF_SI_OWNER_SIBM < < if_si_owner_bit ) ;
2020-10-06 22:03:15 +02:00
pr_emerg ( " Resetting SoC \n " ) ;
2018-11-09 20:57:00 +01:00
2018-01-16 11:12:35 +01:00
writel ( SOFT_CHIP_RST , ctx - > base ) ;
pr_emerg ( " Unable to restart system \n " ) ;
return NOTIFY_DONE ;
}
static int ocelot_reset_probe ( struct platform_device * pdev )
{
struct ocelot_reset_context * ctx ;
struct resource * res ;
struct device * dev = & pdev - > dev ;
int err ;
ctx = devm_kzalloc ( & pdev - > dev , sizeof ( * ctx ) , GFP_KERNEL ) ;
if ( ! ctx )
return - ENOMEM ;
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
ctx - > base = devm_ioremap_resource ( dev , res ) ;
if ( IS_ERR ( ctx - > base ) )
return PTR_ERR ( ctx - > base ) ;
2020-10-06 22:03:15 +02:00
ctx - > props = device_get_match_data ( dev ) ;
ctx - > cpu_ctrl = syscon_regmap_lookup_by_compatible ( ctx - > props - > syscon ) ;
if ( IS_ERR ( ctx - > cpu_ctrl ) ) {
dev_err ( dev , " No syscon map: %s \n " , ctx - > props - > syscon ) ;
2018-01-16 11:12:35 +01:00
return PTR_ERR ( ctx - > cpu_ctrl ) ;
2020-10-06 22:03:15 +02:00
}
2018-01-16 11:12:35 +01:00
ctx - > restart_handler . notifier_call = ocelot_restart_handle ;
ctx - > restart_handler . priority = 192 ;
err = register_restart_handler ( & ctx - > restart_handler ) ;
if ( err )
dev_err ( dev , " can't register restart notifier (err=%d) \n " , err ) ;
return err ;
}
2020-11-25 08:19:19 +01:00
static const struct reset_props reset_props_jaguar2 = {
. syscon = " mscc,ocelot-cpu-syscon " ,
. protect_reg = 0x20 ,
. vcore_protect = BIT ( 2 ) ,
. if_si_owner_bit = 6 ,
} ;
static const struct reset_props reset_props_luton = {
. syscon = " mscc,ocelot-cpu-syscon " ,
. protect_reg = 0x20 ,
. vcore_protect = BIT ( 2 ) ,
. if_si_owner_bit = BIT_OFF_INVALID , /* n/a */
} ;
2020-10-06 22:03:15 +02:00
static const struct reset_props reset_props_ocelot = {
. syscon = " mscc,ocelot-cpu-syscon " ,
. protect_reg = 0x20 ,
. vcore_protect = BIT ( 2 ) ,
. if_si_owner_bit = 4 ,
} ;
static const struct reset_props reset_props_sparx5 = {
. syscon = " microchip,sparx5-cpu-syscon " ,
. protect_reg = 0x84 ,
. vcore_protect = BIT ( 10 ) ,
. if_si_owner_bit = 6 ,
} ;
2018-01-16 11:12:35 +01:00
static const struct of_device_id ocelot_reset_of_match [ ] = {
2020-10-06 22:03:15 +02:00
{
2020-11-25 08:19:19 +01:00
. compatible = " mscc,jaguar2-chip-reset " ,
. data = & reset_props_jaguar2
} , {
. compatible = " mscc,luton-chip-reset " ,
. data = & reset_props_luton
} , {
2020-10-06 22:03:15 +02:00
. compatible = " mscc,ocelot-chip-reset " ,
. data = & reset_props_ocelot
} , {
. compatible = " microchip,sparx5-chip-reset " ,
. data = & reset_props_sparx5
} ,
{ /*sentinel*/ }
2018-01-16 11:12:35 +01:00
} ;
static struct platform_driver ocelot_reset_driver = {
. probe = ocelot_reset_probe ,
. driver = {
. name = " ocelot-chip-reset " ,
. of_match_table = ocelot_reset_of_match ,
} ,
} ;
builtin_platform_driver ( ocelot_reset_driver ) ;