2017-07-19 21:45:11 +03:00
/*
* Copyright ( C ) 2017 Synopsys .
*
2017-08-31 21:06:07 +03:00
* Synopsys HSDK Development platform reset driver .
2017-07-19 21:45:11 +03:00
*
* 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 .
*/
# include <linux/delay.h>
# include <linux/io.h>
# include <linux/iopoll.h>
# include <linux/module.h>
# include <linux/of.h>
# include <linux/platform_device.h>
# include <linux/reset-controller.h>
# include <linux/slab.h>
# include <linux/types.h>
2017-08-31 21:06:07 +03:00
# define to_hsdk_rst(p) container_of((p), struct hsdk_rst, rcdev)
2017-07-19 21:45:11 +03:00
2017-08-31 21:06:07 +03:00
struct hsdk_rst {
2017-07-19 21:45:11 +03:00
void __iomem * regs_ctl ;
void __iomem * regs_rst ;
spinlock_t lock ;
struct reset_controller_dev rcdev ;
} ;
static const u32 rst_map [ ] = {
BIT ( 16 ) , /* APB_RST */
BIT ( 17 ) , /* AXI_RST */
BIT ( 18 ) , /* ETH_RST */
BIT ( 19 ) , /* USB_RST */
BIT ( 20 ) , /* SDIO_RST */
BIT ( 21 ) , /* HDMI_RST */
BIT ( 22 ) , /* GFX_RST */
BIT ( 25 ) , /* DMAC_RST */
BIT ( 31 ) , /* EBI_RST */
} ;
# define HSDK_MAX_RESETS ARRAY_SIZE(rst_map)
# define CGU_SYS_RST_CTRL 0x0
# define CGU_IP_SW_RESET 0x0
# define CGU_IP_SW_RESET_DELAY_SHIFT 16
# define CGU_IP_SW_RESET_DELAY_MASK GENMASK(31, CGU_IP_SW_RESET_DELAY_SHIFT)
# define CGU_IP_SW_RESET_DELAY 0
# define CGU_IP_SW_RESET_RESET BIT(0)
# define SW_RESET_TIMEOUT 10000
2017-08-31 21:06:07 +03:00
static void hsdk_reset_config ( struct hsdk_rst * rst , unsigned long id )
2017-07-19 21:45:11 +03:00
{
writel ( rst_map [ id ] , rst - > regs_ctl + CGU_SYS_RST_CTRL ) ;
}
2017-08-31 21:06:07 +03:00
static int hsdk_reset_do ( struct hsdk_rst * rst )
2017-07-19 21:45:11 +03:00
{
u32 reg ;
reg = readl ( rst - > regs_rst + CGU_IP_SW_RESET ) ;
reg & = ~ CGU_IP_SW_RESET_DELAY_MASK ;
reg | = CGU_IP_SW_RESET_DELAY < < CGU_IP_SW_RESET_DELAY_SHIFT ;
reg | = CGU_IP_SW_RESET_RESET ;
writel ( reg , rst - > regs_rst + CGU_IP_SW_RESET ) ;
/* wait till reset bit is back to 0 */
return readl_poll_timeout_atomic ( rst - > regs_rst + CGU_IP_SW_RESET , reg ,
! ( reg & CGU_IP_SW_RESET_RESET ) , 5 , SW_RESET_TIMEOUT ) ;
}
2017-08-31 21:06:07 +03:00
static int hsdk_reset_reset ( struct reset_controller_dev * rcdev ,
2017-07-19 21:45:11 +03:00
unsigned long id )
{
2017-08-31 21:06:07 +03:00
struct hsdk_rst * rst = to_hsdk_rst ( rcdev ) ;
2017-07-19 21:45:11 +03:00
unsigned long flags ;
int ret ;
spin_lock_irqsave ( & rst - > lock , flags ) ;
2017-08-31 21:06:07 +03:00
hsdk_reset_config ( rst , id ) ;
ret = hsdk_reset_do ( rst ) ;
2017-07-19 21:45:11 +03:00
spin_unlock_irqrestore ( & rst - > lock , flags ) ;
return ret ;
}
2017-08-31 21:06:07 +03:00
static const struct reset_control_ops hsdk_reset_ops = {
. reset = hsdk_reset_reset ,
2018-10-17 17:05:52 +03:00
. deassert = hsdk_reset_reset ,
2017-07-19 21:45:11 +03:00
} ;
2017-08-31 21:06:07 +03:00
static int hsdk_reset_probe ( struct platform_device * pdev )
2017-07-19 21:45:11 +03:00
{
2017-08-31 21:06:07 +03:00
struct hsdk_rst * rst ;
2017-07-19 21:45:11 +03:00
struct resource * mem ;
rst = devm_kzalloc ( & pdev - > dev , sizeof ( * rst ) , GFP_KERNEL ) ;
if ( ! rst )
return - ENOMEM ;
mem = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
rst - > regs_ctl = devm_ioremap_resource ( & pdev - > dev , mem ) ;
if ( IS_ERR ( rst - > regs_ctl ) )
return PTR_ERR ( rst - > regs_ctl ) ;
mem = platform_get_resource ( pdev , IORESOURCE_MEM , 1 ) ;
rst - > regs_rst = devm_ioremap_resource ( & pdev - > dev , mem ) ;
if ( IS_ERR ( rst - > regs_rst ) )
return PTR_ERR ( rst - > regs_rst ) ;
spin_lock_init ( & rst - > lock ) ;
rst - > rcdev . owner = THIS_MODULE ;
2017-08-31 21:06:07 +03:00
rst - > rcdev . ops = & hsdk_reset_ops ;
2017-07-19 21:45:11 +03:00
rst - > rcdev . of_node = pdev - > dev . of_node ;
rst - > rcdev . nr_resets = HSDK_MAX_RESETS ;
rst - > rcdev . of_reset_n_cells = 1 ;
return reset_controller_register ( & rst - > rcdev ) ;
}
2017-08-31 21:06:07 +03:00
static const struct of_device_id hsdk_reset_dt_match [ ] = {
{ . compatible = " snps,hsdk-reset " } ,
2017-07-19 21:45:11 +03:00
{ } ,
} ;
2017-08-31 21:06:07 +03:00
static struct platform_driver hsdk_reset_driver = {
. probe = hsdk_reset_probe ,
2017-07-19 21:45:11 +03:00
. driver = {
2017-08-31 21:06:07 +03:00
. name = " hsdk-reset " ,
. of_match_table = hsdk_reset_dt_match ,
2017-07-19 21:45:11 +03:00
} ,
} ;
2017-08-31 21:06:07 +03:00
builtin_platform_driver ( hsdk_reset_driver ) ;
2017-07-19 21:45:11 +03:00
MODULE_AUTHOR ( " Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com> " ) ;
2017-08-31 21:06:07 +03:00
MODULE_DESCRIPTION ( " Synopsys HSDK SDP reset driver " ) ;
2017-07-19 21:45:11 +03:00
MODULE_LICENSE ( " GPL v2 " ) ;