2019-06-04 10:11:33 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2018-04-09 22:28:31 +03:00
/*
* Copyright ( C ) 2012 NVIDIA CORPORATION . All rights reserved .
*/
2020-11-04 19:49:11 +03:00
# include <linux/of_device.h>
# include <linux/slab.h>
# include <linux/string.h>
2018-04-13 14:33:54 +03:00
# include <dt-bindings/memory/tegra20-mc.h>
2018-04-09 22:28:31 +03:00
# include "mc.h"
static const struct tegra_mc_client tegra20_mc_clients [ ] = {
{
. id = 0x00 ,
. name = " display0a " ,
} , {
. id = 0x01 ,
. name = " display0ab " ,
} , {
. id = 0x02 ,
. name = " display0b " ,
} , {
. id = 0x03 ,
. name = " display0bb " ,
} , {
. id = 0x04 ,
. name = " display0c " ,
} , {
. id = 0x05 ,
. name = " display0cb " ,
} , {
. id = 0x06 ,
. name = " display1b " ,
} , {
. id = 0x07 ,
. name = " display1bb " ,
} , {
. id = 0x08 ,
. name = " eppup " ,
} , {
. id = 0x09 ,
. name = " g2pr " ,
} , {
. id = 0x0a ,
. name = " g2sr " ,
} , {
. id = 0x0b ,
. name = " mpeunifbr " ,
} , {
. id = 0x0c ,
. name = " viruv " ,
} , {
. id = 0x0d ,
. name = " avpcarm7r " ,
} , {
. id = 0x0e ,
. name = " displayhc " ,
} , {
. id = 0x0f ,
. name = " displayhcb " ,
} , {
. id = 0x10 ,
. name = " fdcdrd " ,
} , {
. id = 0x11 ,
. name = " g2dr " ,
} , {
. id = 0x12 ,
. name = " host1xdmar " ,
} , {
. id = 0x13 ,
. name = " host1xr " ,
} , {
. id = 0x14 ,
. name = " idxsrd " ,
} , {
. id = 0x15 ,
. name = " mpcorer " ,
} , {
. id = 0x16 ,
. name = " mpe_ipred " ,
} , {
. id = 0x17 ,
. name = " mpeamemrd " ,
} , {
. id = 0x18 ,
. name = " mpecsrd " ,
} , {
. id = 0x19 ,
. name = " ppcsahbdmar " ,
} , {
. id = 0x1a ,
. name = " ppcsahbslvr " ,
} , {
. id = 0x1b ,
. name = " texsrd " ,
} , {
. id = 0x1c ,
. name = " vdebsevr " ,
} , {
. id = 0x1d ,
. name = " vdember " ,
} , {
. id = 0x1e ,
. name = " vdemcer " ,
} , {
. id = 0x1f ,
. name = " vdetper " ,
} , {
. id = 0x20 ,
. name = " eppu " ,
} , {
. id = 0x21 ,
. name = " eppv " ,
} , {
. id = 0x22 ,
. name = " eppy " ,
} , {
. id = 0x23 ,
. name = " mpeunifbw " ,
} , {
. id = 0x24 ,
. name = " viwsb " ,
} , {
. id = 0x25 ,
. name = " viwu " ,
} , {
. id = 0x26 ,
. name = " viwv " ,
} , {
. id = 0x27 ,
. name = " viwy " ,
} , {
. id = 0x28 ,
. name = " g2dw " ,
} , {
. id = 0x29 ,
. name = " avpcarm7w " ,
} , {
. id = 0x2a ,
. name = " fdcdwr " ,
} , {
. id = 0x2b ,
. name = " host1xw " ,
} , {
. id = 0x2c ,
. name = " ispw " ,
} , {
. id = 0x2d ,
. name = " mpcorew " ,
} , {
. id = 0x2e ,
. name = " mpecswr " ,
} , {
. id = 0x2f ,
. name = " ppcsahbdmaw " ,
} , {
. id = 0x30 ,
. name = " ppcsahbslvw " ,
} , {
. id = 0x31 ,
. name = " vdebsevw " ,
} , {
. id = 0x32 ,
. name = " vdembew " ,
} , {
. id = 0x33 ,
. name = " vdetpmw " ,
} ,
} ;
2018-04-13 14:33:54 +03:00
# define TEGRA20_MC_RESET(_name, _control, _status, _reset, _bit) \
{ \
. name = # _name , \
. id = TEGRA20_MC_RESET_ # # _name , \
. control = _control , \
. status = _status , \
. reset = _reset , \
. bit = _bit , \
}
static const struct tegra_mc_reset tegra20_mc_resets [ ] = {
TEGRA20_MC_RESET ( AVPC , 0x100 , 0x140 , 0x104 , 0 ) ,
TEGRA20_MC_RESET ( DC , 0x100 , 0x144 , 0x104 , 1 ) ,
TEGRA20_MC_RESET ( DCB , 0x100 , 0x148 , 0x104 , 2 ) ,
TEGRA20_MC_RESET ( EPP , 0x100 , 0x14c , 0x104 , 3 ) ,
TEGRA20_MC_RESET ( 2 D , 0x100 , 0x150 , 0x104 , 4 ) ,
TEGRA20_MC_RESET ( HC , 0x100 , 0x154 , 0x104 , 5 ) ,
TEGRA20_MC_RESET ( ISP , 0x100 , 0x158 , 0x104 , 6 ) ,
TEGRA20_MC_RESET ( MPCORE , 0x100 , 0x15c , 0x104 , 7 ) ,
TEGRA20_MC_RESET ( MPEA , 0x100 , 0x160 , 0x104 , 8 ) ,
TEGRA20_MC_RESET ( MPEB , 0x100 , 0x164 , 0x104 , 9 ) ,
TEGRA20_MC_RESET ( MPEC , 0x100 , 0x168 , 0x104 , 10 ) ,
TEGRA20_MC_RESET ( 3 D , 0x100 , 0x16c , 0x104 , 11 ) ,
TEGRA20_MC_RESET ( PPCS , 0x100 , 0x170 , 0x104 , 12 ) ,
TEGRA20_MC_RESET ( VDE , 0x100 , 0x174 , 0x104 , 13 ) ,
TEGRA20_MC_RESET ( VI , 0x100 , 0x178 , 0x104 , 14 ) ,
} ;
2019-04-11 10:48:25 +02:00
static int tegra20_mc_hotreset_assert ( struct tegra_mc * mc ,
2018-04-13 14:33:54 +03:00
const struct tegra_mc_reset * rst )
{
unsigned long flags ;
u32 value ;
spin_lock_irqsave ( & mc - > lock , flags ) ;
value = mc_readl ( mc , rst - > reset ) ;
mc_writel ( mc , value & ~ BIT ( rst - > bit ) , rst - > reset ) ;
spin_unlock_irqrestore ( & mc - > lock , flags ) ;
return 0 ;
}
2019-04-11 10:48:25 +02:00
static int tegra20_mc_hotreset_deassert ( struct tegra_mc * mc ,
2018-04-13 14:33:54 +03:00
const struct tegra_mc_reset * rst )
{
unsigned long flags ;
u32 value ;
spin_lock_irqsave ( & mc - > lock , flags ) ;
value = mc_readl ( mc , rst - > reset ) ;
mc_writel ( mc , value | BIT ( rst - > bit ) , rst - > reset ) ;
spin_unlock_irqrestore ( & mc - > lock , flags ) ;
return 0 ;
}
2019-04-11 10:48:25 +02:00
static int tegra20_mc_block_dma ( struct tegra_mc * mc ,
2018-04-13 14:33:54 +03:00
const struct tegra_mc_reset * rst )
{
unsigned long flags ;
u32 value ;
spin_lock_irqsave ( & mc - > lock , flags ) ;
value = mc_readl ( mc , rst - > control ) & ~ BIT ( rst - > bit ) ;
mc_writel ( mc , value , rst - > control ) ;
spin_unlock_irqrestore ( & mc - > lock , flags ) ;
return 0 ;
}
2019-04-11 10:48:25 +02:00
static bool tegra20_mc_dma_idling ( struct tegra_mc * mc ,
2018-04-13 14:33:54 +03:00
const struct tegra_mc_reset * rst )
{
return mc_readl ( mc , rst - > status ) = = 0 ;
}
2019-04-11 10:48:25 +02:00
static int tegra20_mc_reset_status ( struct tegra_mc * mc ,
2018-04-13 14:33:54 +03:00
const struct tegra_mc_reset * rst )
{
return ( mc_readl ( mc , rst - > reset ) & BIT ( rst - > bit ) ) = = 0 ;
}
2019-04-11 10:48:25 +02:00
static int tegra20_mc_unblock_dma ( struct tegra_mc * mc ,
2018-04-13 14:33:54 +03:00
const struct tegra_mc_reset * rst )
{
unsigned long flags ;
u32 value ;
spin_lock_irqsave ( & mc - > lock , flags ) ;
value = mc_readl ( mc , rst - > control ) | BIT ( rst - > bit ) ;
mc_writel ( mc , value , rst - > control ) ;
spin_unlock_irqrestore ( & mc - > lock , flags ) ;
return 0 ;
}
2019-04-11 10:48:25 +02:00
static const struct tegra_mc_reset_ops tegra20_mc_reset_ops = {
. hotreset_assert = tegra20_mc_hotreset_assert ,
. hotreset_deassert = tegra20_mc_hotreset_deassert ,
. block_dma = tegra20_mc_block_dma ,
. dma_idling = tegra20_mc_dma_idling ,
. unblock_dma = tegra20_mc_unblock_dma ,
. reset_status = tegra20_mc_reset_status ,
2018-04-13 14:33:54 +03:00
} ;
2020-11-04 19:49:11 +03:00
static int tegra20_mc_icc_set ( struct icc_node * src , struct icc_node * dst )
{
/*
* It should be possible to tune arbitration knobs here , but the
* default values are known to work well on all devices . Hence
* nothing to do here so far .
*/
return 0 ;
}
static int tegra20_mc_icc_aggreate ( struct icc_node * node , u32 tag , u32 avg_bw ,
u32 peak_bw , u32 * agg_avg , u32 * agg_peak )
{
/*
* ISO clients need to reserve extra bandwidth up - front because
* there could be high bandwidth pressure during initial filling
* of the client ' s FIFO buffers . Secondly , we need to take into
* account impurities of the memory subsystem .
*/
if ( tag & TEGRA_MC_ICC_TAG_ISO )
peak_bw = tegra_mc_scale_percents ( peak_bw , 300 ) ;
* agg_avg + = avg_bw ;
* agg_peak = max ( * agg_peak , peak_bw ) ;
return 0 ;
}
static struct icc_node_data *
tegra20_mc_of_icc_xlate_extended ( struct of_phandle_args * spec , void * data )
{
struct tegra_mc * mc = icc_provider_to_tegra_mc ( data ) ;
unsigned int i , idx = spec - > args [ 0 ] ;
struct icc_node_data * ndata ;
struct icc_node * node ;
list_for_each_entry ( node , & mc - > provider . nodes , node_list ) {
if ( node - > id ! = idx )
continue ;
ndata = kzalloc ( sizeof ( * ndata ) , GFP_KERNEL ) ;
if ( ! ndata )
return ERR_PTR ( - ENOMEM ) ;
ndata - > node = node ;
/* these clients are isochronous by default */
if ( strstarts ( node - > name , " display " ) | |
strstarts ( node - > name , " vi " ) )
ndata - > tag = TEGRA_MC_ICC_TAG_ISO ;
else
ndata - > tag = TEGRA_MC_ICC_TAG_DEFAULT ;
return ndata ;
}
for ( i = 0 ; i < mc - > soc - > num_clients ; i + + ) {
if ( mc - > soc - > clients [ i ] . id = = idx )
return ERR_PTR ( - EPROBE_DEFER ) ;
}
dev_err ( mc - > dev , " invalid ICC client ID %u \n " , idx ) ;
return ERR_PTR ( - EINVAL ) ;
}
static const struct tegra_mc_icc_ops tegra20_mc_icc_ops = {
. xlate_extended = tegra20_mc_of_icc_xlate_extended ,
. aggregate = tegra20_mc_icc_aggreate ,
. set = tegra20_mc_icc_set ,
} ;
2018-04-09 22:28:31 +03:00
const struct tegra_mc_soc tegra20_mc_soc = {
. clients = tegra20_mc_clients ,
. num_clients = ARRAY_SIZE ( tegra20_mc_clients ) ,
. num_address_bits = 32 ,
. client_id_mask = 0x3f ,
. intmask = MC_INT_SECURITY_VIOLATION | MC_INT_INVALID_GART_PAGE |
MC_INT_DECERR_EMEM ,
2019-04-11 10:48:25 +02:00
. reset_ops = & tegra20_mc_reset_ops ,
2018-04-13 14:33:54 +03:00
. resets = tegra20_mc_resets ,
. num_resets = ARRAY_SIZE ( tegra20_mc_resets ) ,
2020-11-04 19:49:11 +03:00
. icc_ops = & tegra20_mc_icc_ops ,
2018-04-09 22:28:31 +03:00
} ;