2018-10-21 21:30:52 +03:00
// SPDX-License-Identifier: GPL-2.0
/*
* Tegra20 External Memory Controller driver
*
* Author : Dmitry Osipenko < digetx @ gmail . com >
*/
# include <linux/clk.h>
2019-08-12 00:00:31 +03:00
# include <linux/clk/tegra.h>
2019-12-22 14:40:32 +03:00
# include <linux/debugfs.h>
2020-11-11 04:14:34 +03:00
# include <linux/devfreq.h>
2018-10-21 21:30:52 +03:00
# include <linux/err.h>
2020-11-04 19:49:11 +03:00
# include <linux/interconnect-provider.h>
2018-10-21 21:30:52 +03:00
# include <linux/interrupt.h>
2019-08-12 00:00:32 +03:00
# include <linux/io.h>
2020-03-19 22:36:47 +03:00
# include <linux/iopoll.h>
2018-10-21 21:30:52 +03:00
# include <linux/kernel.h>
# include <linux/module.h>
2020-11-04 19:49:11 +03:00
# include <linux/mutex.h>
2018-10-21 21:30:52 +03:00
# include <linux/of.h>
# include <linux/platform_device.h>
2020-11-04 19:49:11 +03:00
# include <linux/pm_opp.h>
# include <linux/slab.h>
2018-10-21 21:30:52 +03:00
# include <linux/sort.h>
# include <linux/types.h>
2020-11-04 19:49:11 +03:00
# include <soc/tegra/common.h>
2018-10-21 21:30:52 +03:00
# include <soc/tegra/fuse.h>
2020-11-04 19:49:11 +03:00
# include "mc.h"
2018-10-21 21:30:52 +03:00
# define EMC_INTSTATUS 0x000
# define EMC_INTMASK 0x004
2019-08-12 00:00:33 +03:00
# define EMC_DBG 0x008
2018-10-21 21:30:52 +03:00
# define EMC_TIMING_CONTROL 0x028
# define EMC_RC 0x02c
# define EMC_RFC 0x030
# define EMC_RAS 0x034
# define EMC_RP 0x038
# define EMC_R2W 0x03c
# define EMC_W2R 0x040
# define EMC_R2P 0x044
# define EMC_W2P 0x048
# define EMC_RD_RCD 0x04c
# define EMC_WR_RCD 0x050
# define EMC_RRD 0x054
# define EMC_REXT 0x058
# define EMC_WDV 0x05c
# define EMC_QUSE 0x060
# define EMC_QRST 0x064
# define EMC_QSAFE 0x068
# define EMC_RDV 0x06c
# define EMC_REFRESH 0x070
# define EMC_BURST_REFRESH_NUM 0x074
# define EMC_PDEX2WR 0x078
# define EMC_PDEX2RD 0x07c
# define EMC_PCHG2PDEN 0x080
# define EMC_ACT2PDEN 0x084
# define EMC_AR2PDEN 0x088
# define EMC_RW2PDEN 0x08c
# define EMC_TXSR 0x090
# define EMC_TCKE 0x094
# define EMC_TFAW 0x098
# define EMC_TRPAB 0x09c
# define EMC_TCLKSTABLE 0x0a0
# define EMC_TCLKSTOP 0x0a4
# define EMC_TREFBW 0x0a8
# define EMC_QUSE_EXTRA 0x0ac
# define EMC_ODT_WRITE 0x0b0
# define EMC_ODT_READ 0x0b4
# define EMC_FBIO_CFG5 0x104
# define EMC_FBIO_CFG6 0x114
2020-11-04 19:49:11 +03:00
# define EMC_STAT_CONTROL 0x160
# define EMC_STAT_LLMC_CONTROL 0x178
# define EMC_STAT_PWR_CLOCK_LIMIT 0x198
# define EMC_STAT_PWR_CLOCKS 0x19c
# define EMC_STAT_PWR_COUNT 0x1a0
2018-10-21 21:30:52 +03:00
# define EMC_AUTO_CAL_INTERVAL 0x2a8
# define EMC_CFG_2 0x2b8
# define EMC_CFG_DIG_DLL 0x2bc
# define EMC_DLL_XFORM_DQS 0x2c0
# define EMC_DLL_XFORM_QUSE 0x2c4
# define EMC_ZCAL_REF_CNT 0x2e0
# define EMC_ZCAL_WAIT_CNT 0x2e4
# define EMC_CFG_CLKTRIM_0 0x2d0
# define EMC_CFG_CLKTRIM_1 0x2d4
# define EMC_CFG_CLKTRIM_2 0x2d8
# define EMC_CLKCHANGE_REQ_ENABLE BIT(0)
# define EMC_CLKCHANGE_PD_ENABLE BIT(1)
# define EMC_CLKCHANGE_SR_ENABLE BIT(2)
# define EMC_TIMING_UPDATE BIT(0)
# define EMC_REFRESH_OVERFLOW_INT BIT(3)
# define EMC_CLKCHANGE_COMPLETE_INT BIT(4)
2019-08-12 00:00:33 +03:00
# define EMC_DBG_READ_MUX_ASSEMBLY BIT(0)
# define EMC_DBG_WRITE_MUX_ACTIVE BIT(1)
# define EMC_DBG_FORCE_UPDATE BIT(2)
# define EMC_DBG_READ_DQM_CTRL BIT(9)
# define EMC_DBG_CFG_PRIORITY BIT(24)
2020-11-04 19:49:11 +03:00
# define EMC_FBIO_CFG5_DRAM_WIDTH_X16 BIT(4)
2020-11-11 04:14:34 +03:00
# define EMC_PWR_GATHER_CLEAR (1 << 8)
# define EMC_PWR_GATHER_DISABLE (2 << 8)
# define EMC_PWR_GATHER_ENABLE (3 << 8)
2018-10-21 21:30:52 +03:00
static const u16 emc_timing_registers [ ] = {
EMC_RC ,
EMC_RFC ,
EMC_RAS ,
EMC_RP ,
EMC_R2W ,
EMC_W2R ,
EMC_R2P ,
EMC_W2P ,
EMC_RD_RCD ,
EMC_WR_RCD ,
EMC_RRD ,
EMC_REXT ,
EMC_WDV ,
EMC_QUSE ,
EMC_QRST ,
EMC_QSAFE ,
EMC_RDV ,
EMC_REFRESH ,
EMC_BURST_REFRESH_NUM ,
EMC_PDEX2WR ,
EMC_PDEX2RD ,
EMC_PCHG2PDEN ,
EMC_ACT2PDEN ,
EMC_AR2PDEN ,
EMC_RW2PDEN ,
EMC_TXSR ,
EMC_TCKE ,
EMC_TFAW ,
EMC_TRPAB ,
EMC_TCLKSTABLE ,
EMC_TCLKSTOP ,
EMC_TREFBW ,
EMC_QUSE_EXTRA ,
EMC_FBIO_CFG6 ,
EMC_ODT_WRITE ,
EMC_ODT_READ ,
EMC_FBIO_CFG5 ,
EMC_CFG_DIG_DLL ,
EMC_DLL_XFORM_DQS ,
EMC_DLL_XFORM_QUSE ,
EMC_ZCAL_REF_CNT ,
EMC_ZCAL_WAIT_CNT ,
EMC_AUTO_CAL_INTERVAL ,
EMC_CFG_CLKTRIM_0 ,
EMC_CFG_CLKTRIM_1 ,
EMC_CFG_CLKTRIM_2 ,
} ;
struct emc_timing {
unsigned long rate ;
u32 data [ ARRAY_SIZE ( emc_timing_registers ) ] ;
} ;
2020-11-04 19:49:11 +03:00
enum emc_rate_request_type {
2020-11-11 04:14:34 +03:00
EMC_RATE_DEVFREQ ,
2020-11-04 19:49:11 +03:00
EMC_RATE_DEBUG ,
EMC_RATE_ICC ,
EMC_RATE_TYPE_MAX ,
} ;
struct emc_rate_request {
unsigned long min_rate ;
unsigned long max_rate ;
} ;
2018-10-21 21:30:52 +03:00
struct tegra_emc {
struct device * dev ;
2020-11-04 19:49:11 +03:00
struct tegra_mc * mc ;
struct icc_provider provider ;
2018-10-21 21:30:52 +03:00
struct notifier_block clk_nb ;
struct clk * clk ;
void __iomem * regs ;
2020-11-04 19:49:11 +03:00
unsigned int dram_bus_width ;
2018-10-21 21:30:52 +03:00
struct emc_timing * timings ;
unsigned int num_timings ;
2019-12-22 14:40:32 +03:00
struct {
struct dentry * root ;
unsigned long min_rate ;
unsigned long max_rate ;
} debugfs ;
2020-11-04 19:49:11 +03:00
/*
* There are multiple sources in the EMC driver which could request
* a min / max clock rate , these rates are contained in this array .
*/
struct emc_rate_request requested_rate [ EMC_RATE_TYPE_MAX ] ;
/* protect shared rate-change code path */
struct mutex rate_lock ;
2020-11-11 04:14:34 +03:00
struct devfreq_simple_ondemand_data ondemand_data ;
2018-10-21 21:30:52 +03:00
} ;
static irqreturn_t tegra_emc_isr ( int irq , void * data )
{
struct tegra_emc * emc = data ;
2020-03-19 22:36:47 +03:00
u32 intmask = EMC_REFRESH_OVERFLOW_INT ;
2018-10-21 21:30:52 +03:00
u32 status ;
status = readl_relaxed ( emc - > regs + EMC_INTSTATUS ) & intmask ;
if ( ! status )
return IRQ_NONE ;
/* notify about HW problem */
if ( status & EMC_REFRESH_OVERFLOW_INT )
dev_err_ratelimited ( emc - > dev ,
" refresh request overflow timeout \n " ) ;
/* clear interrupts */
writel_relaxed ( status , emc - > regs + EMC_INTSTATUS ) ;
return IRQ_HANDLED ;
}
static struct emc_timing * tegra_emc_find_timing ( struct tegra_emc * emc ,
unsigned long rate )
{
struct emc_timing * timing = NULL ;
unsigned int i ;
for ( i = 0 ; i < emc - > num_timings ; i + + ) {
if ( emc - > timings [ i ] . rate > = rate ) {
timing = & emc - > timings [ i ] ;
break ;
}
}
if ( ! timing ) {
dev_err ( emc - > dev , " no timing for rate %lu \n " , rate ) ;
return NULL ;
}
return timing ;
}
static int emc_prepare_timing_change ( struct tegra_emc * emc , unsigned long rate )
{
struct emc_timing * timing = tegra_emc_find_timing ( emc , rate ) ;
unsigned int i ;
if ( ! timing )
return - EINVAL ;
dev_dbg ( emc - > dev , " %s: using timing rate %lu for requested rate %lu \n " ,
__func__ , timing - > rate , rate ) ;
/* program shadow registers */
for ( i = 0 ; i < ARRAY_SIZE ( timing - > data ) ; i + + )
writel_relaxed ( timing - > data [ i ] ,
emc - > regs + emc_timing_registers [ i ] ) ;
/* wait until programming has settled */
readl_relaxed ( emc - > regs + emc_timing_registers [ i - 1 ] ) ;
return 0 ;
}
static int emc_complete_timing_change ( struct tegra_emc * emc , bool flush )
{
2020-03-19 22:36:47 +03:00
int err ;
u32 v ;
2018-10-21 21:30:52 +03:00
dev_dbg ( emc - > dev , " %s: flush %d \n " , __func__ , flush ) ;
if ( flush ) {
/* manually initiate memory timing update */
writel_relaxed ( EMC_TIMING_UPDATE ,
emc - > regs + EMC_TIMING_CONTROL ) ;
return 0 ;
}
2020-03-19 22:36:47 +03:00
err = readl_relaxed_poll_timeout_atomic ( emc - > regs + EMC_INTSTATUS , v ,
v & EMC_CLKCHANGE_COMPLETE_INT ,
1 , 100 ) ;
if ( err ) {
dev_err ( emc - > dev , " emc-car handshake timeout: %d \n " , err ) ;
return err ;
2018-10-21 21:30:52 +03:00
}
return 0 ;
}
static int tegra_emc_clk_change_notify ( struct notifier_block * nb ,
unsigned long msg , void * data )
{
struct tegra_emc * emc = container_of ( nb , struct tegra_emc , clk_nb ) ;
struct clk_notifier_data * cnd = data ;
int err ;
switch ( msg ) {
case PRE_RATE_CHANGE :
err = emc_prepare_timing_change ( emc , cnd - > new_rate ) ;
break ;
case ABORT_RATE_CHANGE :
err = emc_prepare_timing_change ( emc , cnd - > old_rate ) ;
if ( err )
break ;
err = emc_complete_timing_change ( emc , true ) ;
break ;
case POST_RATE_CHANGE :
err = emc_complete_timing_change ( emc , false ) ;
break ;
default :
return NOTIFY_DONE ;
}
return notifier_from_errno ( err ) ;
}
static int load_one_timing_from_dt ( struct tegra_emc * emc ,
struct emc_timing * timing ,
struct device_node * node )
{
u32 rate ;
int err ;
if ( ! of_device_is_compatible ( node , " nvidia,tegra20-emc-table " ) ) {
dev_err ( emc - > dev , " incompatible DT node: %pOF \n " , node ) ;
return - EINVAL ;
}
err = of_property_read_u32 ( node , " clock-frequency " , & rate ) ;
if ( err ) {
dev_err ( emc - > dev , " timing %pOF: failed to read rate: %d \n " ,
node , err ) ;
return err ;
}
err = of_property_read_u32_array ( node , " nvidia,emc-registers " ,
timing - > data ,
ARRAY_SIZE ( emc_timing_registers ) ) ;
if ( err ) {
dev_err ( emc - > dev ,
" timing %pOF: failed to read emc timing data: %d \n " ,
node , err ) ;
return err ;
}
/*
* The EMC clock rate is twice the bus rate , and the bus rate is
* measured in kHz .
*/
timing - > rate = rate * 2 * 1000 ;
dev_dbg ( emc - > dev , " %s: %pOF: EMC rate %lu \n " ,
__func__ , node , timing - > rate ) ;
return 0 ;
}
static int cmp_timings ( const void * _a , const void * _b )
{
const struct emc_timing * a = _a ;
const struct emc_timing * b = _b ;
if ( a - > rate < b - > rate )
return - 1 ;
if ( a - > rate > b - > rate )
return 1 ;
return 0 ;
}
static int tegra_emc_load_timings_from_dt ( struct tegra_emc * emc ,
struct device_node * node )
{
struct device_node * child ;
struct emc_timing * timing ;
int child_count ;
int err ;
child_count = of_get_child_count ( node ) ;
if ( ! child_count ) {
dev_err ( emc - > dev , " no memory timings in DT node: %pOF \n " , node ) ;
return - EINVAL ;
}
emc - > timings = devm_kcalloc ( emc - > dev , child_count , sizeof ( * timing ) ,
GFP_KERNEL ) ;
if ( ! emc - > timings )
return - ENOMEM ;
emc - > num_timings = child_count ;
timing = emc - > timings ;
for_each_child_of_node ( node , child ) {
err = load_one_timing_from_dt ( emc , timing + + , child ) ;
if ( err ) {
of_node_put ( child ) ;
return err ;
}
}
sort ( emc - > timings , emc - > num_timings , sizeof ( * timing ) , cmp_timings ,
NULL ) ;
2021-03-31 02:04:45 +03:00
dev_info_once ( emc - > dev ,
" got %u timings for RAM code %u (min %luMHz max %luMHz) \n " ,
emc - > num_timings ,
tegra_read_ram_code ( ) ,
emc - > timings [ 0 ] . rate / 1000000 ,
emc - > timings [ emc - > num_timings - 1 ] . rate / 1000000 ) ;
2019-08-12 00:00:34 +03:00
2018-10-21 21:30:52 +03:00
return 0 ;
}
static struct device_node *
tegra_emc_find_node_by_ram_code ( struct device * dev )
{
struct device_node * np ;
u32 value , ram_code ;
int err ;
2020-11-04 19:49:10 +03:00
if ( of_get_child_count ( dev - > of_node ) = = 0 ) {
2021-03-31 02:04:45 +03:00
dev_info_once ( dev , " device-tree doesn't have memory timings \n " ) ;
2020-11-04 19:49:10 +03:00
return NULL ;
}
2018-10-21 21:30:52 +03:00
if ( ! of_property_read_bool ( dev - > of_node , " nvidia,use-ram-code " ) )
return of_node_get ( dev - > of_node ) ;
ram_code = tegra_read_ram_code ( ) ;
for ( np = of_find_node_by_name ( dev - > of_node , " emc-tables " ) ; np ;
np = of_find_node_by_name ( np , " emc-tables " ) ) {
err = of_property_read_u32 ( np , " nvidia,ram-code " , & value ) ;
if ( err | | value ! = ram_code ) {
of_node_put ( np ) ;
continue ;
}
return np ;
}
dev_err ( dev , " no memory timings for RAM code %u found in device tree \n " ,
ram_code ) ;
return NULL ;
}
static int emc_setup_hw ( struct tegra_emc * emc )
{
2020-03-19 22:36:47 +03:00
u32 intmask = EMC_REFRESH_OVERFLOW_INT ;
2020-11-04 19:49:11 +03:00
u32 emc_cfg , emc_dbg , emc_fbio ;
2018-10-21 21:30:52 +03:00
emc_cfg = readl_relaxed ( emc - > regs + EMC_CFG_2 ) ;
/*
* Depending on a memory type , DRAM should enter either self - refresh
* or power - down state on EMC clock change .
*/
if ( ! ( emc_cfg & EMC_CLKCHANGE_PD_ENABLE ) & &
! ( emc_cfg & EMC_CLKCHANGE_SR_ENABLE ) ) {
dev_err ( emc - > dev ,
" bootloader didn't specify DRAM auto-suspend mode \n " ) ;
return - EINVAL ;
}
/* enable EMC and CAR to handshake on PLL divider/source changes */
emc_cfg | = EMC_CLKCHANGE_REQ_ENABLE ;
writel_relaxed ( emc_cfg , emc - > regs + EMC_CFG_2 ) ;
/* initialize interrupt */
writel_relaxed ( intmask , emc - > regs + EMC_INTMASK ) ;
writel_relaxed ( intmask , emc - > regs + EMC_INTSTATUS ) ;
2019-08-12 00:00:33 +03:00
/* ensure that unwanted debug features are disabled */
emc_dbg = readl_relaxed ( emc - > regs + EMC_DBG ) ;
emc_dbg | = EMC_DBG_CFG_PRIORITY ;
emc_dbg & = ~ EMC_DBG_READ_MUX_ASSEMBLY ;
emc_dbg & = ~ EMC_DBG_WRITE_MUX_ACTIVE ;
emc_dbg & = ~ EMC_DBG_FORCE_UPDATE ;
writel_relaxed ( emc_dbg , emc - > regs + EMC_DBG ) ;
2020-11-04 19:49:11 +03:00
emc_fbio = readl_relaxed ( emc - > regs + EMC_FBIO_CFG5 ) ;
if ( emc_fbio & EMC_FBIO_CFG5_DRAM_WIDTH_X16 )
emc - > dram_bus_width = 16 ;
else
emc - > dram_bus_width = 32 ;
2021-03-31 02:04:45 +03:00
dev_info_once ( emc - > dev , " %ubit DRAM bus \n " , emc - > dram_bus_width ) ;
2020-11-04 19:49:11 +03:00
2018-10-21 21:30:52 +03:00
return 0 ;
}
2019-08-12 00:00:31 +03:00
static long emc_round_rate ( unsigned long rate ,
unsigned long min_rate ,
unsigned long max_rate ,
void * arg )
{
struct emc_timing * timing = NULL ;
struct tegra_emc * emc = arg ;
unsigned int i ;
2020-11-04 19:49:10 +03:00
if ( ! emc - > num_timings )
return clk_get_rate ( emc - > clk ) ;
2019-08-12 00:00:31 +03:00
min_rate = min ( min_rate , emc - > timings [ emc - > num_timings - 1 ] . rate ) ;
for ( i = 0 ; i < emc - > num_timings ; i + + ) {
if ( emc - > timings [ i ] . rate < rate & & i ! = emc - > num_timings - 1 )
continue ;
if ( emc - > timings [ i ] . rate > max_rate ) {
i = max ( i , 1u ) - 1 ;
if ( emc - > timings [ i ] . rate < min_rate )
break ;
}
if ( emc - > timings [ i ] . rate < min_rate )
continue ;
timing = & emc - > timings [ i ] ;
break ;
}
if ( ! timing ) {
dev_err ( emc - > dev , " no timing for rate %lu min %lu max %lu \n " ,
rate , min_rate , max_rate ) ;
return - EINVAL ;
}
return timing - > rate ;
}
2020-11-04 19:49:11 +03:00
static void tegra_emc_rate_requests_init ( struct tegra_emc * emc )
{
unsigned int i ;
for ( i = 0 ; i < EMC_RATE_TYPE_MAX ; i + + ) {
emc - > requested_rate [ i ] . min_rate = 0 ;
emc - > requested_rate [ i ] . max_rate = ULONG_MAX ;
}
}
static int emc_request_rate ( struct tegra_emc * emc ,
unsigned long new_min_rate ,
unsigned long new_max_rate ,
enum emc_rate_request_type type )
{
struct emc_rate_request * req = emc - > requested_rate ;
unsigned long min_rate = 0 , max_rate = ULONG_MAX ;
unsigned int i ;
int err ;
/* select minimum and maximum rates among the requested rates */
for ( i = 0 ; i < EMC_RATE_TYPE_MAX ; i + + , req + + ) {
if ( i = = type ) {
min_rate = max ( new_min_rate , min_rate ) ;
max_rate = min ( new_max_rate , max_rate ) ;
} else {
min_rate = max ( req - > min_rate , min_rate ) ;
max_rate = min ( req - > max_rate , max_rate ) ;
}
}
if ( min_rate > max_rate ) {
dev_err_ratelimited ( emc - > dev , " %s: type %u: out of range: %lu %lu \n " ,
__func__ , type , min_rate , max_rate ) ;
return - ERANGE ;
}
/*
* EMC rate - changes should go via OPP API because it manages voltage
* changes .
*/
err = dev_pm_opp_set_rate ( emc - > dev , min_rate ) ;
if ( err )
return err ;
emc - > requested_rate [ type ] . min_rate = new_min_rate ;
emc - > requested_rate [ type ] . max_rate = new_max_rate ;
return 0 ;
}
static int emc_set_min_rate ( struct tegra_emc * emc , unsigned long rate ,
enum emc_rate_request_type type )
{
struct emc_rate_request * req = & emc - > requested_rate [ type ] ;
int ret ;
mutex_lock ( & emc - > rate_lock ) ;
ret = emc_request_rate ( emc , rate , req - > max_rate , type ) ;
mutex_unlock ( & emc - > rate_lock ) ;
return ret ;
}
static int emc_set_max_rate ( struct tegra_emc * emc , unsigned long rate ,
enum emc_rate_request_type type )
{
struct emc_rate_request * req = & emc - > requested_rate [ type ] ;
int ret ;
mutex_lock ( & emc - > rate_lock ) ;
ret = emc_request_rate ( emc , req - > min_rate , rate , type ) ;
mutex_unlock ( & emc - > rate_lock ) ;
return ret ;
}
2019-12-22 14:40:32 +03:00
/*
* debugfs interface
*
* The memory controller driver exposes some files in debugfs that can be used
* to control the EMC frequency . The top - level directory can be found here :
*
* / sys / kernel / debug / emc
*
* It contains the following files :
*
* - available_rates : This file contains a list of valid , space - separated
* EMC frequencies .
*
* - min_rate : Writing a value to this file sets the given frequency as the
* floor of the permitted range . If this is higher than the currently
* configured EMC frequency , this will cause the frequency to be
* increased so that it stays within the valid range .
*
* - max_rate : Similarily to the min_rate file , writing a value to this file
* sets the given frequency as the ceiling of the permitted range . If
* the value is lower than the currently configured EMC frequency , this
* will cause the frequency to be decreased so that it stays within the
* valid range .
*/
static bool tegra_emc_validate_rate ( struct tegra_emc * emc , unsigned long rate )
{
unsigned int i ;
for ( i = 0 ; i < emc - > num_timings ; i + + )
if ( rate = = emc - > timings [ i ] . rate )
return true ;
return false ;
}
static int tegra_emc_debug_available_rates_show ( struct seq_file * s , void * data )
{
struct tegra_emc * emc = s - > private ;
const char * prefix = " " ;
unsigned int i ;
for ( i = 0 ; i < emc - > num_timings ; i + + ) {
seq_printf ( s , " %s%lu " , prefix , emc - > timings [ i ] . rate ) ;
prefix = " " ;
}
seq_puts ( s , " \n " ) ;
return 0 ;
}
static int tegra_emc_debug_available_rates_open ( struct inode * inode ,
struct file * file )
{
return single_open ( file , tegra_emc_debug_available_rates_show ,
inode - > i_private ) ;
}
static const struct file_operations tegra_emc_debug_available_rates_fops = {
. open = tegra_emc_debug_available_rates_open ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = single_release ,
} ;
static int tegra_emc_debug_min_rate_get ( void * data , u64 * rate )
{
struct tegra_emc * emc = data ;
* rate = emc - > debugfs . min_rate ;
return 0 ;
}
static int tegra_emc_debug_min_rate_set ( void * data , u64 rate )
{
struct tegra_emc * emc = data ;
int err ;
if ( ! tegra_emc_validate_rate ( emc , rate ) )
return - EINVAL ;
2020-11-04 19:49:11 +03:00
err = emc_set_min_rate ( emc , rate , EMC_RATE_DEBUG ) ;
2019-12-22 14:40:32 +03:00
if ( err < 0 )
return err ;
emc - > debugfs . min_rate = rate ;
return 0 ;
}
DEFINE_SIMPLE_ATTRIBUTE ( tegra_emc_debug_min_rate_fops ,
tegra_emc_debug_min_rate_get ,
tegra_emc_debug_min_rate_set , " %llu \n " ) ;
static int tegra_emc_debug_max_rate_get ( void * data , u64 * rate )
{
struct tegra_emc * emc = data ;
* rate = emc - > debugfs . max_rate ;
return 0 ;
}
static int tegra_emc_debug_max_rate_set ( void * data , u64 rate )
{
struct tegra_emc * emc = data ;
int err ;
if ( ! tegra_emc_validate_rate ( emc , rate ) )
return - EINVAL ;
2020-11-04 19:49:11 +03:00
err = emc_set_max_rate ( emc , rate , EMC_RATE_DEBUG ) ;
2019-12-22 14:40:32 +03:00
if ( err < 0 )
return err ;
emc - > debugfs . max_rate = rate ;
return 0 ;
}
DEFINE_SIMPLE_ATTRIBUTE ( tegra_emc_debug_max_rate_fops ,
tegra_emc_debug_max_rate_get ,
tegra_emc_debug_max_rate_set , " %llu \n " ) ;
static void tegra_emc_debugfs_init ( struct tegra_emc * emc )
{
struct device * dev = emc - > dev ;
unsigned int i ;
int err ;
emc - > debugfs . min_rate = ULONG_MAX ;
emc - > debugfs . max_rate = 0 ;
for ( i = 0 ; i < emc - > num_timings ; i + + ) {
if ( emc - > timings [ i ] . rate < emc - > debugfs . min_rate )
emc - > debugfs . min_rate = emc - > timings [ i ] . rate ;
if ( emc - > timings [ i ] . rate > emc - > debugfs . max_rate )
emc - > debugfs . max_rate = emc - > timings [ i ] . rate ;
}
2020-02-25 02:58:34 +03:00
if ( ! emc - > num_timings ) {
emc - > debugfs . min_rate = clk_get_rate ( emc - > clk ) ;
emc - > debugfs . max_rate = emc - > debugfs . min_rate ;
}
2019-12-22 14:40:32 +03:00
err = clk_set_rate_range ( emc - > clk , emc - > debugfs . min_rate ,
emc - > debugfs . max_rate ) ;
if ( err < 0 ) {
dev_err ( dev , " failed to set rate range [%lu-%lu] for %pC \n " ,
emc - > debugfs . min_rate , emc - > debugfs . max_rate ,
emc - > clk ) ;
}
emc - > debugfs . root = debugfs_create_dir ( " emc " , NULL ) ;
2020-03-13 11:57:39 +03:00
debugfs_create_file ( " available_rates " , 0444 , emc - > debugfs . root ,
2019-12-22 14:40:32 +03:00
emc , & tegra_emc_debug_available_rates_fops ) ;
2020-03-13 11:57:39 +03:00
debugfs_create_file ( " min_rate " , 0644 , emc - > debugfs . root ,
2019-12-22 14:40:32 +03:00
emc , & tegra_emc_debug_min_rate_fops ) ;
2020-03-13 11:57:39 +03:00
debugfs_create_file ( " max_rate " , 0644 , emc - > debugfs . root ,
2019-12-22 14:40:32 +03:00
emc , & tegra_emc_debug_max_rate_fops ) ;
}
2020-11-04 19:49:11 +03:00
static inline struct tegra_emc *
to_tegra_emc_provider ( struct icc_provider * provider )
{
return container_of ( provider , struct tegra_emc , provider ) ;
}
static struct icc_node_data *
emc_of_icc_xlate_extended ( struct of_phandle_args * spec , void * data )
{
struct icc_provider * provider = data ;
struct icc_node_data * ndata ;
struct icc_node * node ;
/* External Memory is the only possible ICC route */
list_for_each_entry ( node , & provider - > nodes , node_list ) {
if ( node - > id ! = TEGRA_ICC_EMEM )
continue ;
ndata = kzalloc ( sizeof ( * ndata ) , GFP_KERNEL ) ;
if ( ! ndata )
return ERR_PTR ( - ENOMEM ) ;
/*
* SRC and DST nodes should have matching TAG in order to have
* it set by default for a requested path .
*/
ndata - > tag = TEGRA_MC_ICC_TAG_ISO ;
ndata - > node = node ;
return ndata ;
}
return ERR_PTR ( - EPROBE_DEFER ) ;
}
static int emc_icc_set ( struct icc_node * src , struct icc_node * dst )
{
struct tegra_emc * emc = to_tegra_emc_provider ( dst - > provider ) ;
unsigned long long peak_bw = icc_units_to_bps ( dst - > peak_bw ) ;
unsigned long long avg_bw = icc_units_to_bps ( dst - > avg_bw ) ;
unsigned long long rate = max ( avg_bw , peak_bw ) ;
unsigned int dram_data_bus_width_bytes ;
int err ;
/*
* Tegra20 EMC runs on x2 clock rate of SDRAM bus because DDR data
* is sampled on both clock edges . This means that EMC clock rate
* equals to the peak data - rate .
*/
dram_data_bus_width_bytes = emc - > dram_bus_width / 8 ;
do_div ( rate , dram_data_bus_width_bytes ) ;
rate = min_t ( u64 , rate , U32_MAX ) ;
err = emc_set_min_rate ( emc , rate , EMC_RATE_ICC ) ;
if ( err )
return err ;
return 0 ;
}
static int tegra_emc_interconnect_init ( struct tegra_emc * emc )
{
const struct tegra_mc_soc * soc ;
struct icc_node * node ;
int err ;
emc - > mc = devm_tegra_memory_controller_get ( emc - > dev ) ;
if ( IS_ERR ( emc - > mc ) )
return PTR_ERR ( emc - > mc ) ;
soc = emc - > mc - > soc ;
emc - > provider . dev = emc - > dev ;
emc - > provider . set = emc_icc_set ;
emc - > provider . data = & emc - > provider ;
emc - > provider . aggregate = soc - > icc_ops - > aggregate ;
emc - > provider . xlate_extended = emc_of_icc_xlate_extended ;
err = icc_provider_add ( & emc - > provider ) ;
if ( err )
goto err_msg ;
/* create External Memory Controller node */
node = icc_node_create ( TEGRA_ICC_EMC ) ;
if ( IS_ERR ( node ) ) {
err = PTR_ERR ( node ) ;
goto del_provider ;
}
node - > name = " External Memory Controller " ;
icc_node_add ( node , & emc - > provider ) ;
/* link External Memory Controller to External Memory (DRAM) */
err = icc_link_create ( node , TEGRA_ICC_EMEM ) ;
if ( err )
goto remove_nodes ;
/* create External Memory node */
node = icc_node_create ( TEGRA_ICC_EMEM ) ;
if ( IS_ERR ( node ) ) {
err = PTR_ERR ( node ) ;
goto remove_nodes ;
}
node - > name = " External Memory (DRAM) " ;
icc_node_add ( node , & emc - > provider ) ;
return 0 ;
remove_nodes :
icc_nodes_remove ( & emc - > provider ) ;
del_provider :
icc_provider_del ( & emc - > provider ) ;
err_msg :
dev_err ( emc - > dev , " failed to initialize ICC: %d \n " , err ) ;
return err ;
}
2020-11-11 04:14:33 +03:00
static void devm_tegra_emc_unset_callback ( void * data )
{
tegra20_clk_set_emc_round_callback ( NULL , NULL ) ;
}
static void devm_tegra_emc_unreg_clk_notifier ( void * data )
{
struct tegra_emc * emc = data ;
clk_notifier_unregister ( emc - > clk , & emc - > clk_nb ) ;
}
static int tegra_emc_init_clk ( struct tegra_emc * emc )
{
int err ;
tegra20_clk_set_emc_round_callback ( emc_round_rate , emc ) ;
err = devm_add_action_or_reset ( emc - > dev , devm_tegra_emc_unset_callback ,
NULL ) ;
if ( err )
return err ;
emc - > clk = devm_clk_get ( emc - > dev , NULL ) ;
if ( IS_ERR ( emc - > clk ) ) {
dev_err ( emc - > dev , " failed to get EMC clock: %pe \n " , emc - > clk ) ;
return PTR_ERR ( emc - > clk ) ;
}
err = clk_notifier_register ( emc - > clk , & emc - > clk_nb ) ;
if ( err ) {
dev_err ( emc - > dev , " failed to register clk notifier: %d \n " , err ) ;
return err ;
}
err = devm_add_action_or_reset ( emc - > dev ,
devm_tegra_emc_unreg_clk_notifier , emc ) ;
if ( err )
return err ;
return 0 ;
}
2020-11-11 04:14:34 +03:00
static int tegra_emc_devfreq_target ( struct device * dev , unsigned long * freq ,
u32 flags )
{
struct tegra_emc * emc = dev_get_drvdata ( dev ) ;
struct dev_pm_opp * opp ;
unsigned long rate ;
opp = devfreq_recommended_opp ( dev , freq , flags ) ;
if ( IS_ERR ( opp ) ) {
dev_err ( dev , " failed to find opp for %lu Hz \n " , * freq ) ;
return PTR_ERR ( opp ) ;
}
rate = dev_pm_opp_get_freq ( opp ) ;
dev_pm_opp_put ( opp ) ;
return emc_set_min_rate ( emc , rate , EMC_RATE_DEVFREQ ) ;
}
static int tegra_emc_devfreq_get_dev_status ( struct device * dev ,
struct devfreq_dev_status * stat )
{
struct tegra_emc * emc = dev_get_drvdata ( dev ) ;
/* freeze counters */
writel_relaxed ( EMC_PWR_GATHER_DISABLE , emc - > regs + EMC_STAT_CONTROL ) ;
/*
* busy_time : number of clocks EMC request was accepted
* total_time : number of clocks PWR_GATHER control was set to ENABLE
*/
stat - > busy_time = readl_relaxed ( emc - > regs + EMC_STAT_PWR_COUNT ) ;
stat - > total_time = readl_relaxed ( emc - > regs + EMC_STAT_PWR_CLOCKS ) ;
stat - > current_frequency = clk_get_rate ( emc - > clk ) ;
/* clear counters and restart */
writel_relaxed ( EMC_PWR_GATHER_CLEAR , emc - > regs + EMC_STAT_CONTROL ) ;
writel_relaxed ( EMC_PWR_GATHER_ENABLE , emc - > regs + EMC_STAT_CONTROL ) ;
return 0 ;
}
static struct devfreq_dev_profile tegra_emc_devfreq_profile = {
. polling_ms = 30 ,
. target = tegra_emc_devfreq_target ,
. get_dev_status = tegra_emc_devfreq_get_dev_status ,
} ;
static int tegra_emc_devfreq_init ( struct tegra_emc * emc )
{
struct devfreq * devfreq ;
/*
* PWR_COUNT is 1 / 2 of PWR_CLOCKS at max , and thus , the up - threshold
* should be less than 50. Secondly , multiple active memory clients
* may cause over 20 % of lost clock cycles due to stalls caused by
* competing memory accesses . This means that threshold should be
* set to a less than 30 in order to have a properly working governor .
*/
emc - > ondemand_data . upthreshold = 20 ;
/*
* Reset statistic gathers state , select global bandwidth for the
* statistics collection mode and set clocks counter saturation
* limit to maximum .
*/
writel_relaxed ( 0x00000000 , emc - > regs + EMC_STAT_CONTROL ) ;
writel_relaxed ( 0x00000000 , emc - > regs + EMC_STAT_LLMC_CONTROL ) ;
writel_relaxed ( 0xffffffff , emc - > regs + EMC_STAT_PWR_CLOCK_LIMIT ) ;
devfreq = devm_devfreq_add_device ( emc - > dev , & tegra_emc_devfreq_profile ,
DEVFREQ_GOV_SIMPLE_ONDEMAND ,
& emc - > ondemand_data ) ;
if ( IS_ERR ( devfreq ) ) {
dev_err ( emc - > dev , " failed to initialize devfreq: %pe " , devfreq ) ;
return PTR_ERR ( devfreq ) ;
}
return 0 ;
}
2018-10-21 21:30:52 +03:00
static int tegra_emc_probe ( struct platform_device * pdev )
{
2021-06-01 05:31:14 +03:00
struct tegra_core_opp_params opp_params = { } ;
2018-10-21 21:30:52 +03:00
struct device_node * np ;
struct tegra_emc * emc ;
int irq , err ;
irq = platform_get_irq ( pdev , 0 ) ;
if ( irq < 0 ) {
dev_err ( & pdev - > dev , " please update your device tree \n " ) ;
return irq ;
}
emc = devm_kzalloc ( & pdev - > dev , sizeof ( * emc ) , GFP_KERNEL ) ;
2020-11-04 19:49:10 +03:00
if ( ! emc )
2018-10-21 21:30:52 +03:00
return - ENOMEM ;
2020-11-04 19:49:11 +03:00
mutex_init ( & emc - > rate_lock ) ;
2018-10-21 21:30:52 +03:00
emc - > clk_nb . notifier_call = tegra_emc_clk_change_notify ;
emc - > dev = & pdev - > dev ;
2020-11-04 19:49:10 +03:00
np = tegra_emc_find_node_by_ram_code ( & pdev - > dev ) ;
if ( np ) {
err = tegra_emc_load_timings_from_dt ( emc , np ) ;
of_node_put ( np ) ;
if ( err )
return err ;
}
2018-10-21 21:30:52 +03:00
2020-11-04 19:49:05 +03:00
emc - > regs = devm_platform_ioremap_resource ( pdev , 0 ) ;
2018-10-21 21:30:52 +03:00
if ( IS_ERR ( emc - > regs ) )
return PTR_ERR ( emc - > regs ) ;
err = emc_setup_hw ( emc ) ;
if ( err )
return err ;
err = devm_request_irq ( & pdev - > dev , irq , tegra_emc_isr , 0 ,
dev_name ( & pdev - > dev ) , emc ) ;
if ( err ) {
2020-11-11 04:14:35 +03:00
dev_err ( & pdev - > dev , " failed to request IRQ: %d \n " , err ) ;
2018-10-21 21:30:52 +03:00
return err ;
}
2020-11-11 04:14:33 +03:00
err = tegra_emc_init_clk ( emc ) ;
if ( err )
return err ;
2018-10-21 21:30:52 +03:00
2021-06-01 05:31:14 +03:00
opp_params . init_state = true ;
err = devm_tegra_core_dev_init_opp_table ( & pdev - > dev , & opp_params ) ;
2020-11-04 19:49:11 +03:00
if ( err )
2020-11-11 04:14:33 +03:00
return err ;
2020-11-04 19:49:11 +03:00
2019-12-22 14:40:32 +03:00
platform_set_drvdata ( pdev , emc ) ;
2020-11-04 19:49:11 +03:00
tegra_emc_rate_requests_init ( emc ) ;
2019-12-22 14:40:32 +03:00
tegra_emc_debugfs_init ( emc ) ;
2020-11-04 19:49:11 +03:00
tegra_emc_interconnect_init ( emc ) ;
2020-11-11 04:14:34 +03:00
tegra_emc_devfreq_init ( emc ) ;
2019-12-22 14:40:32 +03:00
2020-11-04 19:49:09 +03:00
/*
* Don ' t allow the kernel module to be unloaded . Unloading adds some
* extra complexity which doesn ' t really worth the effort in a case of
* this driver .
*/
try_module_get ( THIS_MODULE ) ;
2018-10-21 21:30:52 +03:00
return 0 ;
}
static const struct of_device_id tegra_emc_of_match [ ] = {
{ . compatible = " nvidia,tegra20-emc " , } ,
{ } ,
} ;
2020-11-04 19:49:09 +03:00
MODULE_DEVICE_TABLE ( of , tegra_emc_of_match ) ;
2018-10-21 21:30:52 +03:00
static struct platform_driver tegra_emc_driver = {
. probe = tegra_emc_probe ,
. driver = {
. name = " tegra20-emc " ,
. of_match_table = tegra_emc_of_match ,
. suppress_bind_attrs = true ,
2020-11-04 19:49:11 +03:00
. sync_state = icc_sync_state ,
2018-10-21 21:30:52 +03:00
} ,
} ;
2020-11-04 19:49:09 +03:00
module_platform_driver ( tegra_emc_driver ) ;
2018-10-21 21:30:52 +03:00
2020-11-04 19:49:09 +03:00
MODULE_AUTHOR ( " Dmitry Osipenko <digetx@gmail.com> " ) ;
MODULE_DESCRIPTION ( " NVIDIA Tegra20 EMC driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;