2019-05-29 17:17:56 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2012-05-07 14:24:48 +04:00
/*
* Copyright ( c ) 2012 , NVIDIA CORPORATION . All rights reserved .
* Copyright ( C ) 2011 Google , Inc .
*
* Author :
* Jay Cheng < jacheng @ nvidia . com >
* James Wylder < james . wylder @ motorola . com >
* Benoit Goby < benoit @ android . com >
* Colin Cross < ccross @ android . com >
* Hiroshi DOYU < hdoyu @ nvidia . com >
*/
2013-01-21 14:08:57 +04:00
# include <linux/err.h>
2012-05-07 14:24:48 +04:00
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/platform_device.h>
# include <linux/io.h>
2015-03-26 10:53:57 +03:00
# include <linux/of.h>
2014-07-17 15:17:24 +04:00
# include <soc/tegra/ahb.h>
2012-05-07 14:24:48 +04:00
# define DRV_NAME "tegra-ahb"
2015-03-26 10:53:57 +03:00
# define AHB_ARBITRATION_DISABLE 0x04
# define AHB_ARBITRATION_PRIORITY_CTRL 0x08
2012-05-07 14:24:48 +04:00
# define AHB_PRIORITY_WEIGHT(x) (((x) & 0x7) << 29)
# define PRIORITY_SELECT_USB BIT(6)
# define PRIORITY_SELECT_USB2 BIT(18)
# define PRIORITY_SELECT_USB3 BIT(17)
2015-03-26 10:53:57 +03:00
# define AHB_GIZMO_AHB_MEM 0x10
2012-05-07 14:24:48 +04:00
# define ENB_FAST_REARBITRATE BIT(2)
# define DONT_SPLIT_AHB_WR BIT(7)
2015-03-26 10:53:57 +03:00
# define AHB_GIZMO_APB_DMA 0x14
# define AHB_GIZMO_IDE 0x1c
# define AHB_GIZMO_USB 0x20
# define AHB_GIZMO_AHB_XBAR_BRIDGE 0x24
# define AHB_GIZMO_CPU_AHB_BRIDGE 0x28
# define AHB_GIZMO_COP_AHB_BRIDGE 0x2c
# define AHB_GIZMO_XBAR_APB_CTLR 0x30
# define AHB_GIZMO_VCP_AHB_BRIDGE 0x34
# define AHB_GIZMO_NAND 0x40
# define AHB_GIZMO_SDMMC4 0x48
# define AHB_GIZMO_XIO 0x4c
# define AHB_GIZMO_BSEV 0x64
# define AHB_GIZMO_BSEA 0x74
# define AHB_GIZMO_NOR 0x78
# define AHB_GIZMO_USB2 0x7c
# define AHB_GIZMO_USB3 0x80
2012-05-07 14:24:48 +04:00
# define IMMEDIATE BIT(18)
2015-03-26 10:53:57 +03:00
# define AHB_GIZMO_SDMMC1 0x84
# define AHB_GIZMO_SDMMC2 0x88
# define AHB_GIZMO_SDMMC3 0x8c
# define AHB_MEM_PREFETCH_CFG_X 0xdc
# define AHB_ARBITRATION_XBAR_CTRL 0xe0
# define AHB_MEM_PREFETCH_CFG3 0xe4
# define AHB_MEM_PREFETCH_CFG4 0xe8
# define AHB_MEM_PREFETCH_CFG1 0xf0
# define AHB_MEM_PREFETCH_CFG2 0xf4
2012-05-07 14:24:48 +04:00
# define PREFETCH_ENB BIT(31)
# define MST_ID(x) (((x) & 0x1f) << 26)
# define AHBDMA_MST_ID MST_ID(5)
# define USB_MST_ID MST_ID(6)
# define USB2_MST_ID MST_ID(18)
# define USB3_MST_ID MST_ID(17)
# define ADDR_BNDRY(x) (((x) & 0xf) << 21)
# define INACTIVITY_TIMEOUT(x) (((x) & 0xffff) << 0)
2015-03-26 10:53:57 +03:00
# define AHB_ARBITRATION_AHB_MEM_WRQUE_MST_ID 0xfc
2012-05-07 14:24:48 +04:00
2012-05-07 10:43:46 +04:00
# define AHB_ARBITRATION_XBAR_CTRL_SMMU_INIT_DONE BIT(17)
2015-03-26 10:56:35 +03:00
/*
* INCORRECT_BASE_ADDR_LOW_BYTE : Legacy kernel DT files for Tegra SoCs
* prior to Tegra124 generally use a physical base address ending in
* 0x4 for the AHB IP block . According to the TRM , the low byte
* should be 0x0 . During device probing , this macro is used to detect
* whether the passed - in physical address is incorrect , and if so , to
* correct it .
*/
# define INCORRECT_BASE_ADDR_LOW_BYTE 0x4
2012-05-07 10:43:46 +04:00
static struct platform_driver tegra_ahb_driver ;
2012-05-07 14:24:48 +04:00
static const u32 tegra_ahb_gizmo [ ] = {
AHB_ARBITRATION_DISABLE ,
AHB_ARBITRATION_PRIORITY_CTRL ,
AHB_GIZMO_AHB_MEM ,
AHB_GIZMO_APB_DMA ,
AHB_GIZMO_IDE ,
AHB_GIZMO_USB ,
AHB_GIZMO_AHB_XBAR_BRIDGE ,
AHB_GIZMO_CPU_AHB_BRIDGE ,
AHB_GIZMO_COP_AHB_BRIDGE ,
AHB_GIZMO_XBAR_APB_CTLR ,
AHB_GIZMO_VCP_AHB_BRIDGE ,
AHB_GIZMO_NAND ,
AHB_GIZMO_SDMMC4 ,
AHB_GIZMO_XIO ,
AHB_GIZMO_BSEV ,
AHB_GIZMO_BSEA ,
AHB_GIZMO_NOR ,
AHB_GIZMO_USB2 ,
AHB_GIZMO_USB3 ,
AHB_GIZMO_SDMMC1 ,
AHB_GIZMO_SDMMC2 ,
AHB_GIZMO_SDMMC3 ,
AHB_MEM_PREFETCH_CFG_X ,
AHB_ARBITRATION_XBAR_CTRL ,
AHB_MEM_PREFETCH_CFG3 ,
AHB_MEM_PREFETCH_CFG4 ,
AHB_MEM_PREFETCH_CFG1 ,
AHB_MEM_PREFETCH_CFG2 ,
AHB_ARBITRATION_AHB_MEM_WRQUE_MST_ID ,
} ;
struct tegra_ahb {
void __iomem * regs ;
struct device * dev ;
2020-05-28 17:35:11 +03:00
u32 ctx [ ] ;
2012-05-07 14:24:48 +04:00
} ;
static inline u32 gizmo_readl ( struct tegra_ahb * ahb , u32 offset )
{
2015-03-26 10:56:35 +03:00
return readl ( ahb - > regs + offset ) ;
2012-05-07 14:24:48 +04:00
}
static inline void gizmo_writel ( struct tegra_ahb * ahb , u32 value , u32 offset )
{
2015-03-26 10:56:35 +03:00
writel ( value , ahb - > regs + offset ) ;
2012-05-07 14:24:48 +04:00
}
2013-02-06 23:12:35 +04:00
# ifdef CONFIG_TEGRA_IOMMU_SMMU
2012-05-07 10:43:46 +04:00
int tegra_ahb_enable_smmu ( struct device_node * dn )
{
struct device * dev ;
u32 val ;
struct tegra_ahb * ahb ;
2019-07-24 01:18:33 +03:00
dev = driver_find_device_by_of_node ( & tegra_ahb_driver . driver , dn ) ;
2012-05-07 10:43:46 +04:00
if ( ! dev )
return - EPROBE_DEFER ;
ahb = dev_get_drvdata ( dev ) ;
val = gizmo_readl ( ahb , AHB_ARBITRATION_XBAR_CTRL ) ;
val | = AHB_ARBITRATION_XBAR_CTRL_SMMU_INIT_DONE ;
gizmo_writel ( ahb , val , AHB_ARBITRATION_XBAR_CTRL ) ;
return 0 ;
}
EXPORT_SYMBOL ( tegra_ahb_enable_smmu ) ;
# endif
2019-04-26 17:56:03 +03:00
static int __maybe_unused tegra_ahb_suspend ( struct device * dev )
2012-05-07 14:24:48 +04:00
{
int i ;
struct tegra_ahb * ahb = dev_get_drvdata ( dev ) ;
for ( i = 0 ; i < ARRAY_SIZE ( tegra_ahb_gizmo ) ; i + + )
ahb - > ctx [ i ] = gizmo_readl ( ahb , tegra_ahb_gizmo [ i ] ) ;
return 0 ;
}
2019-04-26 17:56:03 +03:00
static int __maybe_unused tegra_ahb_resume ( struct device * dev )
2012-05-07 14:24:48 +04:00
{
int i ;
struct tegra_ahb * ahb = dev_get_drvdata ( dev ) ;
for ( i = 0 ; i < ARRAY_SIZE ( tegra_ahb_gizmo ) ; i + + )
gizmo_writel ( ahb , ahb - > ctx [ i ] , tegra_ahb_gizmo [ i ] ) ;
return 0 ;
}
static UNIVERSAL_DEV_PM_OPS ( tegra_ahb_pm ,
tegra_ahb_suspend ,
tegra_ahb_resume , NULL ) ;
static void tegra_ahb_gizmo_init ( struct tegra_ahb * ahb )
{
u32 val ;
val = gizmo_readl ( ahb , AHB_GIZMO_AHB_MEM ) ;
val | = ENB_FAST_REARBITRATE | IMMEDIATE | DONT_SPLIT_AHB_WR ;
gizmo_writel ( ahb , val , AHB_GIZMO_AHB_MEM ) ;
val = gizmo_readl ( ahb , AHB_GIZMO_USB ) ;
val | = IMMEDIATE ;
gizmo_writel ( ahb , val , AHB_GIZMO_USB ) ;
val = gizmo_readl ( ahb , AHB_GIZMO_USB2 ) ;
val | = IMMEDIATE ;
gizmo_writel ( ahb , val , AHB_GIZMO_USB2 ) ;
val = gizmo_readl ( ahb , AHB_GIZMO_USB3 ) ;
val | = IMMEDIATE ;
gizmo_writel ( ahb , val , AHB_GIZMO_USB3 ) ;
val = gizmo_readl ( ahb , AHB_ARBITRATION_PRIORITY_CTRL ) ;
val | = PRIORITY_SELECT_USB |
PRIORITY_SELECT_USB2 |
PRIORITY_SELECT_USB3 |
AHB_PRIORITY_WEIGHT ( 7 ) ;
gizmo_writel ( ahb , val , AHB_ARBITRATION_PRIORITY_CTRL ) ;
val = gizmo_readl ( ahb , AHB_MEM_PREFETCH_CFG1 ) ;
val & = ~ MST_ID ( ~ 0 ) ;
val | = PREFETCH_ENB |
AHBDMA_MST_ID |
ADDR_BNDRY ( 0xc ) |
INACTIVITY_TIMEOUT ( 0x1000 ) ;
gizmo_writel ( ahb , val , AHB_MEM_PREFETCH_CFG1 ) ;
val = gizmo_readl ( ahb , AHB_MEM_PREFETCH_CFG2 ) ;
val & = ~ MST_ID ( ~ 0 ) ;
val | = PREFETCH_ENB |
USB_MST_ID |
ADDR_BNDRY ( 0xc ) |
INACTIVITY_TIMEOUT ( 0x1000 ) ;
gizmo_writel ( ahb , val , AHB_MEM_PREFETCH_CFG2 ) ;
val = gizmo_readl ( ahb , AHB_MEM_PREFETCH_CFG3 ) ;
val & = ~ MST_ID ( ~ 0 ) ;
val | = PREFETCH_ENB |
USB3_MST_ID |
ADDR_BNDRY ( 0xc ) |
INACTIVITY_TIMEOUT ( 0x1000 ) ;
gizmo_writel ( ahb , val , AHB_MEM_PREFETCH_CFG3 ) ;
val = gizmo_readl ( ahb , AHB_MEM_PREFETCH_CFG4 ) ;
val & = ~ MST_ID ( ~ 0 ) ;
val | = PREFETCH_ENB |
USB2_MST_ID |
ADDR_BNDRY ( 0xc ) |
INACTIVITY_TIMEOUT ( 0x1000 ) ;
gizmo_writel ( ahb , val , AHB_MEM_PREFETCH_CFG4 ) ;
}
2012-12-22 01:16:42 +04:00
static int tegra_ahb_probe ( struct platform_device * pdev )
2012-05-07 14:24:48 +04:00
{
struct resource * res ;
struct tegra_ahb * ahb ;
size_t bytes ;
bytes = sizeof ( * ahb ) + sizeof ( u32 ) * ARRAY_SIZE ( tegra_ahb_gizmo ) ;
ahb = devm_kzalloc ( & pdev - > dev , bytes , GFP_KERNEL ) ;
if ( ! ahb )
return - ENOMEM ;
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
2015-03-26 10:56:35 +03:00
/* Correct the IP block base address if necessary */
if ( res & &
( res - > start & INCORRECT_BASE_ADDR_LOW_BYTE ) = =
INCORRECT_BASE_ADDR_LOW_BYTE ) {
dev_warn ( & pdev - > dev , " incorrect AHB base address in DT data - enabling workaround \n " ) ;
res - > start - = INCORRECT_BASE_ADDR_LOW_BYTE ;
}
2013-01-21 14:08:57 +04:00
ahb - > regs = devm_ioremap_resource ( & pdev - > dev , res ) ;
if ( IS_ERR ( ahb - > regs ) )
return PTR_ERR ( ahb - > regs ) ;
2012-05-07 14:24:48 +04:00
ahb - > dev = & pdev - > dev ;
platform_set_drvdata ( pdev , ahb ) ;
tegra_ahb_gizmo_init ( ahb ) ;
return 0 ;
}
2012-12-22 01:16:42 +04:00
static const struct of_device_id tegra_ahb_of_match [ ] = {
2012-05-07 14:24:48 +04:00
{ . compatible = " nvidia,tegra30-ahb " , } ,
{ . compatible = " nvidia,tegra20-ahb " , } ,
{ } ,
} ;
static struct platform_driver tegra_ahb_driver = {
. probe = tegra_ahb_probe ,
. driver = {
. name = DRV_NAME ,
. of_match_table = tegra_ahb_of_match ,
. pm = & tegra_ahb_pm ,
} ,
} ;
module_platform_driver ( tegra_ahb_driver ) ;
MODULE_AUTHOR ( " Hiroshi DOYU <hdoyu@nvidia.com> " ) ;
MODULE_DESCRIPTION ( " Tegra AHB driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_ALIAS ( " platform: " DRV_NAME ) ;