2019-05-29 17:17:59 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2017-02-21 19:13:31 +03:00
/*
* Copyright ( c ) 2017 , Impinj , Inc .
*
* i . MX7 System Reset Controller ( SRC ) driver
*
* Author : Andrey Smirnov < andrew . smirnov @ gmail . com >
*/
# include <linux/mfd/syscon.h>
2018-06-20 08:47:28 +03:00
# include <linux/mod_devicetable.h>
2019-01-22 05:10:41 +03:00
# include <linux/of_device.h>
2017-02-21 19:13:31 +03:00
# include <linux/platform_device.h>
# include <linux/reset-controller.h>
# include <linux/regmap.h>
# include <dt-bindings/reset/imx7-reset.h>
2019-01-22 05:10:43 +03:00
# include <dt-bindings/reset/imx8mq-reset.h>
2017-02-21 19:13:31 +03:00
2019-01-22 05:10:41 +03:00
struct imx7_src_signal {
unsigned int offset , bit ;
} ;
struct imx7_src_variant {
const struct imx7_src_signal * signals ;
unsigned int signals_num ;
struct reset_control_ops ops ;
} ;
2017-02-21 19:13:31 +03:00
struct imx7_src {
struct reset_controller_dev rcdev ;
struct regmap * regmap ;
2019-01-22 05:10:41 +03:00
const struct imx7_src_signal * signals ;
2017-02-21 19:13:31 +03:00
} ;
enum imx7_src_registers {
SRC_A7RCR0 = 0x0004 ,
SRC_M4RCR = 0x000c ,
SRC_ERCR = 0x0014 ,
SRC_HSICPHY_RCR = 0x001c ,
SRC_USBOPHY1_RCR = 0x0020 ,
SRC_USBOPHY2_RCR = 0x0024 ,
SRC_MIPIPHY_RCR = 0x0028 ,
SRC_PCIEPHY_RCR = 0x002c ,
SRC_DDRC_RCR = 0x1000 ,
} ;
2019-01-22 05:10:41 +03:00
static int imx7_reset_update ( struct imx7_src * imx7src ,
unsigned long id , unsigned int value )
{
const struct imx7_src_signal * signal = & imx7src - > signals [ id ] ;
return regmap_update_bits ( imx7src - > regmap ,
signal - > offset , signal - > bit , value ) ;
}
2017-02-21 19:13:31 +03:00
static const struct imx7_src_signal imx7_src_signals [ IMX7_RESET_NUM ] = {
[ IMX7_RESET_A7_CORE_POR_RESET0 ] = { SRC_A7RCR0 , BIT ( 0 ) } ,
[ IMX7_RESET_A7_CORE_POR_RESET1 ] = { SRC_A7RCR0 , BIT ( 1 ) } ,
[ IMX7_RESET_A7_CORE_RESET0 ] = { SRC_A7RCR0 , BIT ( 4 ) } ,
[ IMX7_RESET_A7_CORE_RESET1 ] = { SRC_A7RCR0 , BIT ( 5 ) } ,
[ IMX7_RESET_A7_DBG_RESET0 ] = { SRC_A7RCR0 , BIT ( 8 ) } ,
[ IMX7_RESET_A7_DBG_RESET1 ] = { SRC_A7RCR0 , BIT ( 9 ) } ,
[ IMX7_RESET_A7_ETM_RESET0 ] = { SRC_A7RCR0 , BIT ( 12 ) } ,
[ IMX7_RESET_A7_ETM_RESET1 ] = { SRC_A7RCR0 , BIT ( 13 ) } ,
[ IMX7_RESET_A7_SOC_DBG_RESET ] = { SRC_A7RCR0 , BIT ( 20 ) } ,
[ IMX7_RESET_A7_L2RESET ] = { SRC_A7RCR0 , BIT ( 21 ) } ,
[ IMX7_RESET_SW_M4C_RST ] = { SRC_M4RCR , BIT ( 1 ) } ,
[ IMX7_RESET_SW_M4P_RST ] = { SRC_M4RCR , BIT ( 2 ) } ,
[ IMX7_RESET_EIM_RST ] = { SRC_ERCR , BIT ( 0 ) } ,
[ IMX7_RESET_HSICPHY_PORT_RST ] = { SRC_HSICPHY_RCR , BIT ( 1 ) } ,
[ IMX7_RESET_USBPHY1_POR ] = { SRC_USBOPHY1_RCR , BIT ( 0 ) } ,
[ IMX7_RESET_USBPHY1_PORT_RST ] = { SRC_USBOPHY1_RCR , BIT ( 1 ) } ,
[ IMX7_RESET_USBPHY2_POR ] = { SRC_USBOPHY2_RCR , BIT ( 0 ) } ,
[ IMX7_RESET_USBPHY2_PORT_RST ] = { SRC_USBOPHY2_RCR , BIT ( 1 ) } ,
[ IMX7_RESET_MIPI_PHY_MRST ] = { SRC_MIPIPHY_RCR , BIT ( 1 ) } ,
[ IMX7_RESET_MIPI_PHY_SRST ] = { SRC_MIPIPHY_RCR , BIT ( 2 ) } ,
[ IMX7_RESET_PCIEPHY ] = { SRC_PCIEPHY_RCR , BIT ( 2 ) | BIT ( 1 ) } ,
[ IMX7_RESET_PCIEPHY_PERST ] = { SRC_PCIEPHY_RCR , BIT ( 3 ) } ,
[ IMX7_RESET_PCIE_CTRL_APPS_EN ] = { SRC_PCIEPHY_RCR , BIT ( 6 ) } ,
2018-07-11 22:30:02 +03:00
[ IMX7_RESET_PCIE_CTRL_APPS_TURNOFF ] = { SRC_PCIEPHY_RCR , BIT ( 11 ) } ,
2017-02-21 19:13:31 +03:00
[ IMX7_RESET_DDRC_PRST ] = { SRC_DDRC_RCR , BIT ( 0 ) } ,
[ IMX7_RESET_DDRC_CORE_RST ] = { SRC_DDRC_RCR , BIT ( 1 ) } ,
} ;
static struct imx7_src * to_imx7_src ( struct reset_controller_dev * rcdev )
{
return container_of ( rcdev , struct imx7_src , rcdev ) ;
}
static int imx7_reset_set ( struct reset_controller_dev * rcdev ,
unsigned long id , bool assert )
{
struct imx7_src * imx7src = to_imx7_src ( rcdev ) ;
2019-01-22 05:10:41 +03:00
const unsigned int bit = imx7src - > signals [ id ] . bit ;
unsigned int value = assert ? bit : 0 ;
2017-02-21 19:13:31 +03:00
switch ( id ) {
case IMX7_RESET_PCIEPHY :
/*
* wait for more than 10u s to release phy g_rst and
* btnrst
*/
if ( ! assert )
udelay ( 10 ) ;
break ;
case IMX7_RESET_PCIE_CTRL_APPS_EN :
2019-01-22 05:10:41 +03:00
value = assert ? 0 : bit ;
2017-02-21 19:13:31 +03:00
break ;
}
2019-01-22 05:10:41 +03:00
return imx7_reset_update ( imx7src , id , value ) ;
2017-02-21 19:13:31 +03:00
}
static int imx7_reset_assert ( struct reset_controller_dev * rcdev ,
unsigned long id )
{
return imx7_reset_set ( rcdev , id , true ) ;
}
static int imx7_reset_deassert ( struct reset_controller_dev * rcdev ,
unsigned long id )
{
return imx7_reset_set ( rcdev , id , false ) ;
}
2019-01-22 05:10:41 +03:00
static const struct imx7_src_variant variant_imx7 = {
. signals = imx7_src_signals ,
. signals_num = ARRAY_SIZE ( imx7_src_signals ) ,
. ops = {
. assert = imx7_reset_assert ,
. deassert = imx7_reset_deassert ,
} ,
2017-02-21 19:13:31 +03:00
} ;
2019-01-22 05:10:43 +03:00
enum imx8mq_src_registers {
SRC_A53RCR0 = 0x0004 ,
SRC_HDMI_RCR = 0x0030 ,
SRC_DISP_RCR = 0x0034 ,
SRC_GPU_RCR = 0x0040 ,
SRC_VPU_RCR = 0x0044 ,
SRC_PCIE2_RCR = 0x0048 ,
SRC_MIPIPHY1_RCR = 0x004c ,
SRC_MIPIPHY2_RCR = 0x0050 ,
SRC_DDRC2_RCR = 0x1004 ,
} ;
static const struct imx7_src_signal imx8mq_src_signals [ IMX8MQ_RESET_NUM ] = {
[ IMX8MQ_RESET_A53_CORE_POR_RESET0 ] = { SRC_A53RCR0 , BIT ( 0 ) } ,
[ IMX8MQ_RESET_A53_CORE_POR_RESET1 ] = { SRC_A53RCR0 , BIT ( 1 ) } ,
[ IMX8MQ_RESET_A53_CORE_POR_RESET2 ] = { SRC_A53RCR0 , BIT ( 2 ) } ,
[ IMX8MQ_RESET_A53_CORE_POR_RESET3 ] = { SRC_A53RCR0 , BIT ( 3 ) } ,
[ IMX8MQ_RESET_A53_CORE_RESET0 ] = { SRC_A53RCR0 , BIT ( 4 ) } ,
[ IMX8MQ_RESET_A53_CORE_RESET1 ] = { SRC_A53RCR0 , BIT ( 5 ) } ,
[ IMX8MQ_RESET_A53_CORE_RESET2 ] = { SRC_A53RCR0 , BIT ( 6 ) } ,
[ IMX8MQ_RESET_A53_CORE_RESET3 ] = { SRC_A53RCR0 , BIT ( 7 ) } ,
[ IMX8MQ_RESET_A53_DBG_RESET0 ] = { SRC_A53RCR0 , BIT ( 8 ) } ,
[ IMX8MQ_RESET_A53_DBG_RESET1 ] = { SRC_A53RCR0 , BIT ( 9 ) } ,
[ IMX8MQ_RESET_A53_DBG_RESET2 ] = { SRC_A53RCR0 , BIT ( 10 ) } ,
[ IMX8MQ_RESET_A53_DBG_RESET3 ] = { SRC_A53RCR0 , BIT ( 11 ) } ,
[ IMX8MQ_RESET_A53_ETM_RESET0 ] = { SRC_A53RCR0 , BIT ( 12 ) } ,
[ IMX8MQ_RESET_A53_ETM_RESET1 ] = { SRC_A53RCR0 , BIT ( 13 ) } ,
[ IMX8MQ_RESET_A53_ETM_RESET2 ] = { SRC_A53RCR0 , BIT ( 14 ) } ,
[ IMX8MQ_RESET_A53_ETM_RESET3 ] = { SRC_A53RCR0 , BIT ( 15 ) } ,
[ IMX8MQ_RESET_A53_SOC_DBG_RESET ] = { SRC_A53RCR0 , BIT ( 20 ) } ,
[ IMX8MQ_RESET_A53_L2RESET ] = { SRC_A53RCR0 , BIT ( 21 ) } ,
[ IMX8MQ_RESET_SW_NON_SCLR_M4C_RST ] = { SRC_M4RCR , BIT ( 0 ) } ,
[ IMX8MQ_RESET_OTG1_PHY_RESET ] = { SRC_USBOPHY1_RCR , BIT ( 0 ) } ,
[ IMX8MQ_RESET_OTG2_PHY_RESET ] = { SRC_USBOPHY2_RCR , BIT ( 0 ) } ,
[ IMX8MQ_RESET_MIPI_DSI_RESET_BYTE_N ] = { SRC_MIPIPHY_RCR , BIT ( 1 ) } ,
[ IMX8MQ_RESET_MIPI_DSI_RESET_N ] = { SRC_MIPIPHY_RCR , BIT ( 2 ) } ,
[ IMX8MQ_RESET_MIPI_DIS_DPI_RESET_N ] = { SRC_MIPIPHY_RCR , BIT ( 3 ) } ,
[ IMX8MQ_RESET_MIPI_DIS_ESC_RESET_N ] = { SRC_MIPIPHY_RCR , BIT ( 4 ) } ,
[ IMX8MQ_RESET_MIPI_DIS_PCLK_RESET_N ] = { SRC_MIPIPHY_RCR , BIT ( 5 ) } ,
[ IMX8MQ_RESET_PCIEPHY ] = { SRC_PCIEPHY_RCR ,
BIT ( 2 ) | BIT ( 1 ) } ,
[ IMX8MQ_RESET_PCIEPHY_PERST ] = { SRC_PCIEPHY_RCR , BIT ( 3 ) } ,
[ IMX8MQ_RESET_PCIE_CTRL_APPS_EN ] = { SRC_PCIEPHY_RCR , BIT ( 6 ) } ,
[ IMX8MQ_RESET_PCIE_CTRL_APPS_TURNOFF ] = { SRC_PCIEPHY_RCR , BIT ( 11 ) } ,
[ IMX8MQ_RESET_HDMI_PHY_APB_RESET ] = { SRC_HDMI_RCR , BIT ( 0 ) } ,
[ IMX8MQ_RESET_DISP_RESET ] = { SRC_DISP_RCR , BIT ( 0 ) } ,
[ IMX8MQ_RESET_GPU_RESET ] = { SRC_GPU_RCR , BIT ( 0 ) } ,
[ IMX8MQ_RESET_VPU_RESET ] = { SRC_VPU_RCR , BIT ( 0 ) } ,
[ IMX8MQ_RESET_PCIEPHY2 ] = { SRC_PCIE2_RCR ,
BIT ( 2 ) | BIT ( 1 ) } ,
[ IMX8MQ_RESET_PCIEPHY2_PERST ] = { SRC_PCIE2_RCR , BIT ( 3 ) } ,
[ IMX8MQ_RESET_PCIE2_CTRL_APPS_EN ] = { SRC_PCIE2_RCR , BIT ( 6 ) } ,
[ IMX8MQ_RESET_PCIE2_CTRL_APPS_TURNOFF ] = { SRC_PCIE2_RCR , BIT ( 11 ) } ,
[ IMX8MQ_RESET_MIPI_CSI1_CORE_RESET ] = { SRC_MIPIPHY1_RCR , BIT ( 0 ) } ,
[ IMX8MQ_RESET_MIPI_CSI1_PHY_REF_RESET ] = { SRC_MIPIPHY1_RCR , BIT ( 1 ) } ,
[ IMX8MQ_RESET_MIPI_CSI1_ESC_RESET ] = { SRC_MIPIPHY1_RCR , BIT ( 2 ) } ,
[ IMX8MQ_RESET_MIPI_CSI2_CORE_RESET ] = { SRC_MIPIPHY2_RCR , BIT ( 0 ) } ,
[ IMX8MQ_RESET_MIPI_CSI2_PHY_REF_RESET ] = { SRC_MIPIPHY2_RCR , BIT ( 1 ) } ,
[ IMX8MQ_RESET_MIPI_CSI2_ESC_RESET ] = { SRC_MIPIPHY2_RCR , BIT ( 2 ) } ,
[ IMX8MQ_RESET_DDRC1_PRST ] = { SRC_DDRC_RCR , BIT ( 0 ) } ,
[ IMX8MQ_RESET_DDRC1_CORE_RESET ] = { SRC_DDRC_RCR , BIT ( 1 ) } ,
[ IMX8MQ_RESET_DDRC1_PHY_RESET ] = { SRC_DDRC_RCR , BIT ( 2 ) } ,
[ IMX8MQ_RESET_DDRC2_PHY_RESET ] = { SRC_DDRC2_RCR , BIT ( 0 ) } ,
[ IMX8MQ_RESET_DDRC2_CORE_RESET ] = { SRC_DDRC2_RCR , BIT ( 1 ) } ,
[ IMX8MQ_RESET_DDRC2_PRST ] = { SRC_DDRC2_RCR , BIT ( 2 ) } ,
} ;
static int imx8mq_reset_set ( struct reset_controller_dev * rcdev ,
unsigned long id , bool assert )
{
struct imx7_src * imx7src = to_imx7_src ( rcdev ) ;
const unsigned int bit = imx7src - > signals [ id ] . bit ;
unsigned int value = assert ? bit : 0 ;
switch ( id ) {
case IMX8MQ_RESET_PCIEPHY :
case IMX8MQ_RESET_PCIEPHY2 : /* fallthrough */
/*
* wait for more than 10u s to release phy g_rst and
* btnrst
*/
if ( ! assert )
udelay ( 10 ) ;
break ;
case IMX8MQ_RESET_PCIE_CTRL_APPS_EN :
case IMX8MQ_RESET_PCIE2_CTRL_APPS_EN : /* fallthrough */
case IMX8MQ_RESET_MIPI_DIS_PCLK_RESET_N : /* fallthrough */
case IMX8MQ_RESET_MIPI_DIS_ESC_RESET_N : /* fallthrough */
case IMX8MQ_RESET_MIPI_DIS_DPI_RESET_N : /* fallthrough */
case IMX8MQ_RESET_MIPI_DSI_RESET_N : /* fallthrough */
case IMX8MQ_RESET_MIPI_DSI_RESET_BYTE_N : /* fallthrough */
value = assert ? 0 : bit ;
break ;
}
return imx7_reset_update ( imx7src , id , value ) ;
}
static int imx8mq_reset_assert ( struct reset_controller_dev * rcdev ,
unsigned long id )
{
return imx8mq_reset_set ( rcdev , id , true ) ;
}
static int imx8mq_reset_deassert ( struct reset_controller_dev * rcdev ,
unsigned long id )
{
return imx8mq_reset_set ( rcdev , id , false ) ;
}
static const struct imx7_src_variant variant_imx8mq = {
. signals = imx8mq_src_signals ,
. signals_num = ARRAY_SIZE ( imx8mq_src_signals ) ,
. ops = {
. assert = imx8mq_reset_assert ,
. deassert = imx8mq_reset_deassert ,
} ,
} ;
2017-02-21 19:13:31 +03:00
static int imx7_reset_probe ( struct platform_device * pdev )
{
struct imx7_src * imx7src ;
struct device * dev = & pdev - > dev ;
struct regmap_config config = { . name = " src " } ;
2019-01-22 05:10:41 +03:00
const struct imx7_src_variant * variant = of_device_get_match_data ( dev ) ;
2017-02-21 19:13:31 +03:00
imx7src = devm_kzalloc ( dev , sizeof ( * imx7src ) , GFP_KERNEL ) ;
if ( ! imx7src )
return - ENOMEM ;
2019-01-22 05:10:41 +03:00
imx7src - > signals = variant - > signals ;
2017-02-21 19:13:31 +03:00
imx7src - > regmap = syscon_node_to_regmap ( dev - > of_node ) ;
if ( IS_ERR ( imx7src - > regmap ) ) {
dev_err ( dev , " Unable to get imx7-src regmap " ) ;
return PTR_ERR ( imx7src - > regmap ) ;
}
regmap_attach_dev ( dev , imx7src - > regmap , & config ) ;
imx7src - > rcdev . owner = THIS_MODULE ;
2019-01-22 05:10:41 +03:00
imx7src - > rcdev . nr_resets = variant - > signals_num ;
imx7src - > rcdev . ops = & variant - > ops ;
2017-02-21 19:13:31 +03:00
imx7src - > rcdev . of_node = dev - > of_node ;
return devm_reset_controller_register ( dev , & imx7src - > rcdev ) ;
}
static const struct of_device_id imx7_reset_dt_ids [ ] = {
2019-01-22 05:10:41 +03:00
{ . compatible = " fsl,imx7d-src " , . data = & variant_imx7 } ,
2019-01-22 05:10:43 +03:00
{ . compatible = " fsl,imx8mq-src " , . data = & variant_imx8mq } ,
2017-02-21 19:13:31 +03:00
{ /* sentinel */ } ,
} ;
static struct platform_driver imx7_reset_driver = {
. probe = imx7_reset_probe ,
. driver = {
. name = KBUILD_MODNAME ,
. of_match_table = imx7_reset_dt_ids ,
} ,
} ;
builtin_platform_driver ( imx7_reset_driver ) ;