2014-07-02 17:46:58 +02:00
/*
2015-09-10 12:35:13 +02:00
* Atmel AT91 SAM9 & SAMA5 SoCs reset code
2014-07-02 17:46:58 +02:00
*
* Copyright ( C ) 2007 Atmel Corporation .
* Copyright ( C ) BitBox Ltd 2010
* Copyright ( C ) 2011 Jean - Christophe PLAGNIOL - VILLARD < plagnioj @ jcosoft . com >
* Copyright ( C ) 2014 Free Electrons
*
* 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 .
*/
2015-08-11 11:12:48 +02:00
# include <linux/clk.h>
2014-07-02 17:46:58 +02:00
# include <linux/io.h>
# include <linux/module.h>
# include <linux/of_address.h>
# include <linux/platform_device.h>
# include <linux/reboot.h>
2022-06-10 12:24:12 +03:00
# include <linux/reset-controller.h>
2023-06-20 08:26:57 +02:00
# include <linux/power/power_on_reason.h>
2014-07-02 17:46:58 +02:00
2014-11-07 21:58:21 +01:00
# include <soc/at91/at91sam9_ddrsdr.h>
# include <soc/at91/at91sam9_sdramc.h>
2014-07-02 17:46:58 +02:00
2022-06-10 12:24:13 +03:00
# include <dt-bindings/reset/sama7g5-reset.h>
2014-07-02 17:46:58 +02:00
# define AT91_RSTC_CR 0x00 /* Reset Controller Control Register */
# define AT91_RSTC_PROCRST BIT(0) /* Processor Reset */
# define AT91_RSTC_PERRST BIT(2) /* Peripheral Reset */
# define AT91_RSTC_EXTRST BIT(3) /* External Reset */
# define AT91_RSTC_KEY (0xa5 << 24) /* KEY Password */
# define AT91_RSTC_SR 0x04 /* Reset Controller Status Register */
# define AT91_RSTC_URSTS BIT(0) /* User Reset Status */
# define AT91_RSTC_RSTTYP GENMASK(10, 8) /* Reset Type */
# define AT91_RSTC_NRSTL BIT(16) /* NRST Pin Level */
# define AT91_RSTC_SRCMP BIT(17) /* Software Reset Command in Progress */
# define AT91_RSTC_MR 0x08 /* Reset Controller Mode Register */
# define AT91_RSTC_URSTEN BIT(0) /* User Reset Enable */
2020-01-21 10:03:39 +00:00
# define AT91_RSTC_URSTASYNC BIT(2) /* User Reset Asynchronous Control */
2014-07-02 17:46:58 +02:00
# define AT91_RSTC_URSTIEN BIT(4) /* User Reset Interrupt Enable */
# define AT91_RSTC_ERSTL GENMASK(11, 8) /* External Reset Length */
2022-06-10 12:24:10 +03:00
/**
* enum reset_type - reset types
* @ RESET_TYPE_GENERAL : first power - up reset
* @ RESET_TYPE_WAKEUP : return from backup mode
* @ RESET_TYPE_WATCHDOG : watchdog fault
* @ RESET_TYPE_SOFTWARE : processor reset required by software
* @ RESET_TYPE_USER : NRST pin detected low
* @ RESET_TYPE_CPU_FAIL : CPU clock failure detection
* @ RESET_TYPE_XTAL_FAIL : 32 KHz crystal failure dectection fault
* @ RESET_TYPE_ULP2 : ULP2 reset
*/
2014-07-02 17:46:58 +02:00
enum reset_type {
RESET_TYPE_GENERAL = 0 ,
RESET_TYPE_WAKEUP = 1 ,
RESET_TYPE_WATCHDOG = 2 ,
RESET_TYPE_SOFTWARE = 3 ,
RESET_TYPE_USER = 4 ,
2019-02-06 19:12:21 +01:00
RESET_TYPE_CPU_FAIL = 6 ,
RESET_TYPE_XTAL_FAIL = 7 ,
RESET_TYPE_ULP2 = 8 ,
2014-07-02 17:46:58 +02:00
} ;
2022-06-10 12:24:10 +03:00
/**
* struct at91_reset - AT91 reset specific data structure
* @ rstc_base : base address for system reset
* @ ramc_base : array with base addresses of RAM controllers
2022-06-10 12:24:12 +03:00
* @ dev_base : base address for devices reset
2022-06-10 12:24:10 +03:00
* @ sclk : slow clock
2022-06-10 12:24:11 +03:00
* @ data : platform specific reset data
2022-06-10 12:24:12 +03:00
* @ rcdev : reset controller device
* @ lock : lock for devices reset register access
2022-06-10 12:24:10 +03:00
* @ nb : reset notifier block
* @ args : SoC specific system reset arguments
* @ ramc_lpr : SDRAM Controller Low Power Register
*/
2020-01-21 10:03:29 +00:00
struct at91_reset {
void __iomem * rstc_base ;
2020-01-21 10:03:30 +00:00
void __iomem * ramc_base [ 2 ] ;
2022-06-10 12:24:12 +03:00
void __iomem * dev_base ;
2020-01-21 10:03:30 +00:00
struct clk * sclk ;
2022-06-10 12:24:11 +03:00
const struct at91_reset_data * data ;
2022-06-10 12:24:12 +03:00
struct reset_controller_dev rcdev ;
spinlock_t lock ;
2020-01-21 10:03:31 +00:00
struct notifier_block nb ;
2020-01-21 10:03:33 +00:00
u32 args ;
2020-01-21 10:03:34 +00:00
u32 ramc_lpr ;
2020-01-21 10:03:29 +00:00
} ;
2022-06-10 12:24:12 +03:00
# define to_at91_reset(r) container_of(r, struct at91_reset, rcdev)
2022-06-10 12:24:11 +03:00
/**
* struct at91_reset_data - AT91 reset data
* @ reset_args : SoC specific system reset arguments
* @ n_device_reset : number of device resets
* @ device_reset_min_id : min id for device reset
* @ device_reset_max_id : max id for device reset
*/
struct at91_reset_data {
u32 reset_args ;
u32 n_device_reset ;
u8 device_reset_min_id ;
u8 device_reset_max_id ;
} ;
2014-07-02 17:46:58 +02:00
/*
* unless the SDRAM is cleanly shutdown before we hit the
* reset register it can be left driving the data bus and
* killing the chance of a subsequent boot from NAND
*/
2020-01-21 10:03:38 +00:00
static int at91_reset ( struct notifier_block * this , unsigned long mode ,
void * cmd )
2014-07-02 17:46:58 +02:00
{
2020-01-21 10:03:32 +00:00
struct at91_reset * reset = container_of ( this , struct at91_reset , nb ) ;
2014-07-02 17:46:58 +02:00
asm volatile (
/* Align to cache lines */
" .balign 32 \n \t "
/* Disable SDRAM0 accesses */
2020-01-21 10:03:37 +00:00
" tst %0, #0 \n \t "
" beq 1f \n \t "
" str %3, [%0, # " __stringify ( AT91_DDRSDRC_RTR ) " ] \n \t "
2014-07-02 17:46:58 +02:00
/* Power down SDRAM0 */
2020-01-21 10:03:34 +00:00
" str %4, [%0, %6] \n \t "
2014-07-02 17:46:58 +02:00
/* Disable SDRAM1 accesses */
2020-01-21 10:03:37 +00:00
" 1: tst %1, #0 \n \t "
" beq 2f \n \t "
2014-07-02 17:46:58 +02:00
" strne %3, [%1, # " __stringify ( AT91_DDRSDRC_RTR ) " ] \n \t "
/* Power down SDRAM1 */
2020-01-21 10:03:34 +00:00
" strne %4, [%1, %6] \n \t "
2014-07-02 17:46:58 +02:00
/* Reset CPU */
2020-01-21 10:03:37 +00:00
" 2: str %5, [%2, # " __stringify ( AT91_RSTC_CR ) " ] \n \t "
2014-07-02 17:46:58 +02:00
" b . \n \t "
:
2020-01-21 10:03:31 +00:00
: " r " ( reset - > ramc_base [ 0 ] ) ,
" r " ( reset - > ramc_base [ 1 ] ) ,
" r " ( reset - > rstc_base ) ,
2014-07-02 17:46:58 +02:00
" r " ( 1 ) ,
2015-03-26 14:16:22 +00:00
" r " cpu_to_le32 ( AT91_DDRSDRC_LPCB_POWER_DOWN ) ,
2022-06-10 12:24:11 +03:00
" r " ( reset - > data - > reset_args ) ,
2020-01-21 10:03:34 +00:00
" r " ( reset - > ramc_lpr )
2020-01-21 10:03:33 +00:00
: " r4 " ) ;
2015-01-25 12:30:41 -08:00
return NOTIFY_DONE ;
2014-07-02 17:46:58 +02:00
}
2023-06-20 08:26:57 +02:00
static const char * at91_reset_reason ( struct at91_reset * reset )
2014-07-02 17:46:58 +02:00
{
2023-06-16 15:52:51 +02:00
u32 reg = readl ( reset - > rstc_base + AT91_RSTC_SR ) ;
2018-03-16 11:06:26 +01:00
const char * reason ;
2014-07-02 17:46:58 +02:00
switch ( ( reg & AT91_RSTC_RSTTYP ) > > 8 ) {
case RESET_TYPE_GENERAL :
2023-06-20 08:26:57 +02:00
reason = POWER_ON_REASON_REGULAR ;
2014-07-02 17:46:58 +02:00
break ;
case RESET_TYPE_WAKEUP :
2023-06-20 08:26:57 +02:00
reason = POWER_ON_REASON_RTC ;
2014-07-02 17:46:58 +02:00
break ;
case RESET_TYPE_WATCHDOG :
2023-06-20 08:26:57 +02:00
reason = POWER_ON_REASON_WATCHDOG ;
2014-07-02 17:46:58 +02:00
break ;
case RESET_TYPE_SOFTWARE :
2023-06-20 08:26:57 +02:00
reason = POWER_ON_REASON_SOFTWARE ;
2014-07-02 17:46:58 +02:00
break ;
case RESET_TYPE_USER :
2023-06-20 08:26:57 +02:00
reason = POWER_ON_REASON_RST_BTN ;
2014-07-02 17:46:58 +02:00
break ;
2019-02-06 19:12:21 +01:00
case RESET_TYPE_CPU_FAIL :
2023-06-20 08:26:57 +02:00
reason = POWER_ON_REASON_CPU_CLK_FAIL ;
2019-02-06 19:12:21 +01:00
break ;
case RESET_TYPE_XTAL_FAIL :
2023-06-20 08:26:57 +02:00
reason = POWER_ON_REASON_XTAL_FAIL ;
2019-02-06 19:12:21 +01:00
break ;
case RESET_TYPE_ULP2 :
2023-06-20 08:26:57 +02:00
reason = POWER_ON_REASON_BROWN_OUT ;
2019-02-06 19:12:21 +01:00
break ;
2014-07-02 17:46:58 +02:00
default :
2023-06-20 08:26:57 +02:00
reason = POWER_ON_REASON_UNKNOWN ;
2014-07-02 17:46:58 +02:00
break ;
}
2023-06-16 15:52:51 +02:00
return reason ;
2014-07-02 17:46:58 +02:00
}
2023-06-20 08:26:57 +02:00
static ssize_t power_on_reason_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct platform_device * pdev = to_platform_device ( dev ) ;
struct at91_reset * reset = platform_get_drvdata ( pdev ) ;
return sprintf ( buf , " %s \n " , at91_reset_reason ( reset ) ) ;
}
static DEVICE_ATTR_RO ( power_on_reason ) ;
2015-03-16 20:17:12 +01:00
static const struct of_device_id at91_ramc_of_match [ ] = {
2020-01-21 10:03:34 +00:00
{
. compatible = " atmel,at91sam9260-sdramc " ,
. data = ( void * ) AT91_SDRAMC_LPR ,
} ,
{
. compatible = " atmel,at91sam9g45-ddramc " ,
. data = ( void * ) AT91_DDRSDRC_LPR ,
} ,
2014-07-02 17:46:58 +02:00
{ /* sentinel */ }
} ;
2022-06-10 12:24:11 +03:00
static const struct at91_reset_data sam9260 = {
. reset_args = AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST ,
} ;
static const struct at91_reset_data samx7 = {
. reset_args = AT91_RSTC_KEY | AT91_RSTC_PROCRST ,
} ;
2022-06-10 12:24:13 +03:00
static const struct at91_reset_data sama7g5 = {
. reset_args = AT91_RSTC_KEY | AT91_RSTC_PROCRST ,
. n_device_reset = 3 ,
. device_reset_min_id = SAMA7G5_RESET_USB_PHY1 ,
. device_reset_max_id = SAMA7G5_RESET_USB_PHY3 ,
} ;
2015-03-16 20:17:12 +01:00
static const struct of_device_id at91_reset_of_match [ ] = {
2020-01-21 10:03:32 +00:00
{
. compatible = " atmel,at91sam9260-rstc " ,
2022-06-10 12:24:11 +03:00
. data = & sam9260 ,
2020-01-21 10:03:32 +00:00
} ,
{
. compatible = " atmel,at91sam9g45-rstc " ,
2022-06-10 12:24:11 +03:00
. data = & sam9260 ,
2020-01-21 10:03:32 +00:00
} ,
{
. compatible = " atmel,sama5d3-rstc " ,
2022-06-10 12:24:11 +03:00
. data = & sam9260 ,
2020-01-21 10:03:32 +00:00
} ,
{
. compatible = " atmel,samx7-rstc " ,
2022-06-10 12:24:11 +03:00
. data = & samx7 ,
2020-01-21 10:03:32 +00:00
} ,
{
. compatible = " microchip,sam9x60-rstc " ,
2022-06-10 12:24:11 +03:00
. data = & samx7 ,
2020-01-21 10:03:32 +00:00
} ,
2022-06-10 12:24:13 +03:00
{
. compatible = " microchip,sama7g5-rstc " ,
. data = & sama7g5 ,
} ,
2014-07-02 17:46:58 +02:00
{ /* sentinel */ }
} ;
2016-10-17 15:36:12 -03:00
MODULE_DEVICE_TABLE ( of , at91_reset_of_match ) ;
2014-07-02 17:46:58 +02:00
2022-06-10 12:24:12 +03:00
static int at91_reset_update ( struct reset_controller_dev * rcdev ,
unsigned long id , bool assert )
{
struct at91_reset * reset = to_at91_reset ( rcdev ) ;
unsigned long flags ;
u32 val ;
spin_lock_irqsave ( & reset - > lock , flags ) ;
val = readl_relaxed ( reset - > dev_base ) ;
if ( assert )
val | = BIT ( id ) ;
else
val & = ~ BIT ( id ) ;
writel_relaxed ( val , reset - > dev_base ) ;
spin_unlock_irqrestore ( & reset - > lock , flags ) ;
return 0 ;
}
static int at91_reset_assert ( struct reset_controller_dev * rcdev ,
unsigned long id )
{
return at91_reset_update ( rcdev , id , true ) ;
}
static int at91_reset_deassert ( struct reset_controller_dev * rcdev ,
unsigned long id )
{
return at91_reset_update ( rcdev , id , false ) ;
}
static int at91_reset_dev_status ( struct reset_controller_dev * rcdev ,
unsigned long id )
{
struct at91_reset * reset = to_at91_reset ( rcdev ) ;
u32 val ;
val = readl_relaxed ( reset - > dev_base ) ;
return ! ! ( val & BIT ( id ) ) ;
}
static const struct reset_control_ops at91_reset_ops = {
. assert = at91_reset_assert ,
. deassert = at91_reset_deassert ,
. status = at91_reset_dev_status ,
} ;
static int at91_reset_of_xlate ( struct reset_controller_dev * rcdev ,
const struct of_phandle_args * reset_spec )
{
struct at91_reset * reset = to_at91_reset ( rcdev ) ;
if ( ! reset - > data - > n_device_reset | |
( reset_spec - > args [ 0 ] < reset - > data - > device_reset_min_id | |
reset_spec - > args [ 0 ] > reset - > data - > device_reset_max_id ) )
return - EINVAL ;
return reset_spec - > args [ 0 ] ;
}
static int at91_rcdev_init ( struct at91_reset * reset ,
struct platform_device * pdev )
{
if ( ! reset - > data - > n_device_reset )
return 0 ;
reset - > dev_base = devm_of_iomap ( & pdev - > dev , pdev - > dev . of_node , 1 ,
NULL ) ;
if ( IS_ERR ( reset - > dev_base ) )
return - ENODEV ;
spin_lock_init ( & reset - > lock ) ;
reset - > rcdev . ops = & at91_reset_ops ;
reset - > rcdev . owner = THIS_MODULE ;
reset - > rcdev . of_node = pdev - > dev . of_node ;
reset - > rcdev . nr_resets = reset - > data - > n_device_reset ;
reset - > rcdev . of_reset_n_cells = 1 ;
reset - > rcdev . of_xlate = at91_reset_of_xlate ;
return devm_reset_controller_register ( & pdev - > dev , & reset - > rcdev ) ;
}
2023-11-04 22:15:04 +01:00
static int at91_reset_probe ( struct platform_device * pdev )
2014-07-02 17:46:58 +02:00
{
const struct of_device_id * match ;
2020-01-21 10:03:32 +00:00
struct at91_reset * reset ;
2014-07-02 17:46:58 +02:00
struct device_node * np ;
2015-08-11 11:12:46 +02:00
int ret , idx = 0 ;
2014-07-02 17:46:58 +02:00
2020-01-21 10:03:31 +00:00
reset = devm_kzalloc ( & pdev - > dev , sizeof ( * reset ) , GFP_KERNEL ) ;
if ( ! reset )
return - ENOMEM ;
2021-04-02 13:50:18 +03:00
reset - > rstc_base = devm_of_iomap ( & pdev - > dev , pdev - > dev . of_node , 0 , NULL ) ;
2021-09-30 13:09:28 +03:00
if ( IS_ERR ( reset - > rstc_base ) ) {
2014-07-02 17:46:58 +02:00
dev_err ( & pdev - > dev , " Could not map reset controller address \n " ) ;
return - ENODEV ;
}
2015-07-20 17:32:05 +08:00
if ( ! of_device_is_compatible ( pdev - > dev . of_node , " atmel,sama5d3-rstc " ) ) {
/* we need to shutdown the ddr controller, so get ramc base */
2020-01-21 10:03:34 +00:00
for_each_matching_node_and_match ( np , at91_ramc_of_match , & match ) {
reset - > ramc_lpr = ( u32 ) match - > data ;
2021-04-02 13:50:18 +03:00
reset - > ramc_base [ idx ] = devm_of_iomap ( & pdev - > dev , np , 0 , NULL ) ;
2021-09-30 13:09:28 +03:00
if ( IS_ERR ( reset - > ramc_base [ idx ] ) ) {
2015-07-20 17:32:05 +08:00
dev_err ( & pdev - > dev , " Could not map ram controller address \n " ) ;
2015-11-18 23:04:14 +01:00
of_node_put ( np ) ;
2015-07-20 17:32:05 +08:00
return - ENODEV ;
}
idx + + ;
2014-07-02 17:46:58 +02:00
}
}
2022-06-10 12:24:11 +03:00
reset - > data = device_get_match_data ( & pdev - > dev ) ;
if ( ! reset - > data )
return - ENODEV ;
2020-01-21 10:03:38 +00:00
reset - > nb . notifier_call = at91_reset ;
2020-01-21 10:03:31 +00:00
reset - > nb . priority = 192 ;
2014-07-02 17:46:58 +02:00
2020-01-21 10:03:31 +00:00
reset - > sclk = devm_clk_get ( & pdev - > dev , NULL ) ;
if ( IS_ERR ( reset - > sclk ) )
return PTR_ERR ( reset - > sclk ) ;
2015-08-11 11:12:48 +02:00
2020-01-21 10:03:31 +00:00
ret = clk_prepare_enable ( reset - > sclk ) ;
2015-08-11 11:12:48 +02:00
if ( ret ) {
dev_err ( & pdev - > dev , " Could not enable slow clock \n " ) ;
return ret ;
}
2020-01-21 10:03:32 +00:00
platform_set_drvdata ( pdev , reset ) ;
2022-06-10 12:24:12 +03:00
ret = at91_rcdev_init ( reset , pdev ) ;
if ( ret )
goto disable_clk ;
2020-01-21 10:03:39 +00:00
if ( of_device_is_compatible ( pdev - > dev . of_node , " microchip,sam9x60-rstc " ) ) {
u32 val = readl ( reset - > rstc_base + AT91_RSTC_MR ) ;
writel ( AT91_RSTC_KEY | AT91_RSTC_URSTASYNC | val ,
reset - > rstc_base + AT91_RSTC_MR ) ;
}
2020-01-21 10:03:31 +00:00
ret = register_restart_handler ( & reset - > nb ) ;
2022-06-10 12:24:12 +03:00
if ( ret )
goto disable_clk ;
2014-07-02 17:46:58 +02:00
2023-06-20 08:26:57 +02:00
ret = device_create_file ( & pdev - > dev , & dev_attr_power_on_reason ) ;
if ( ret ) {
dev_err ( & pdev - > dev , " Could not create sysfs entry \n " ) ;
return ret ;
}
2023-06-16 15:52:51 +02:00
dev_info ( & pdev - > dev , " Starting after %s \n " , at91_reset_reason ( reset ) ) ;
2014-07-02 17:46:58 +02:00
return 0 ;
2022-06-10 12:24:12 +03:00
disable_clk :
clk_disable_unprepare ( reset - > sclk ) ;
return ret ;
2014-07-02 17:46:58 +02:00
}
2023-11-04 22:15:04 +01:00
static int at91_reset_remove ( struct platform_device * pdev )
2015-08-11 11:12:47 +02:00
{
2020-01-21 10:03:32 +00:00
struct at91_reset * reset = platform_get_drvdata ( pdev ) ;
2020-01-21 10:03:31 +00:00
unregister_restart_handler ( & reset - > nb ) ;
clk_disable_unprepare ( reset - > sclk ) ;
2015-08-11 11:12:47 +02:00
return 0 ;
}
2014-07-02 17:46:58 +02:00
static struct platform_driver at91_reset_driver = {
2023-11-04 22:15:04 +01:00
. probe = at91_reset_probe ,
. remove = at91_reset_remove ,
2014-07-02 17:46:58 +02:00
. driver = {
. name = " at91-reset " ,
. of_match_table = at91_reset_of_match ,
} ,
} ;
2023-11-04 22:15:04 +01:00
module_platform_driver ( at91_reset_driver ) ;
2015-08-11 11:12:47 +02:00
MODULE_AUTHOR ( " Atmel Corporation " ) ;
MODULE_DESCRIPTION ( " Reset driver for Atmel SoCs " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;