blob: c2d321c652c49bd3ec12e2dbf2039dad051b9f25 [file] [log] [blame]
/*
* arch/arm/mach-tegra/tegra11_emc.c
*
* Copyright (c) 2011-2014, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/platform_data/tegra_emc.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/hrtimer.h>
#include <asm/cputime.h>
#include <mach/iomap.h>
#include "clock.h"
#include "dvfs.h"
#include "board.h"
#include "tegra11_emc.h"
#include "fuse.h"
#include "tegra-board-id.h"
#ifdef CONFIG_TEGRA_EMC_SCALING_ENABLE
static bool emc_enable = true;
#else
static bool emc_enable;
#endif
module_param(emc_enable, bool, 0644);
static u32 bw_calc_freqs_lpddr3[] = {
20000, 40000, 60000, 80000, 100000,
120000, 140000, 160000, 180000, 200000,
220000, 240000, 260000, 280000, 300000
};
static u32 tegra11_lpddr3_emc_usage_share_default[] = {
/* TODO. May need to be more conservative */
28, 35, 38, 40, 41, 42, 43, 43, 45, 45, 45, 46, 47, 48, 48,
/* When >300MHz BW is requested, assume 50% for default */
50
};
static u32 tegra11_lpddr3_emc_usage_share_dc[] = {
/* TODO. May need to be more conservative */
35, 47, 52, 55, 57, 58, 59, 60, 62, 62, 63, 64, 66, 67, 68,
/* When >300MHz BW is requested, assume 70% for dc only */
70
};
static u8 iso_share_calc_t114_lpddr3_default(unsigned long iso_bw);
static u8 iso_share_calc_t114_lpddr3_dc(unsigned long iso_bw);
static u32 bw_calc_freqs_ddr3[] = {
20000, 40000, 60000, 80000, 100000,
120000, 140000, 160000, 180000, 200000,
220000, 240000, 260000, 280000, 300000
};
static u32 tegra11_ddr3_emc_usage_share_default[] = {
28, 35, 38, 40, 41, 42, 43, 43, 45, 45, 45, 46, 47, 48, 48,
/* When >300MHz BW is requested, assume 50% for default */
50
};
static u32 tegra11_ddr3_emc_usage_share_dc[] = {
35, 47, 52, 55, 57, 58, 59, 60, 62, 62, 63, 64, 66, 67, 68,
/* When >300MHz BW is requested, assume 70% for dc only */
70
};
static u8 iso_share_calc_t114_ddr3_default(unsigned long iso_bw);
static u8 iso_share_calc_t114_ddr3_dc(unsigned long iso_bw);
u8 tegra_emc_bw_efficiency = 80;
static struct emc_iso_usage tegra11_lpddr3_emc_iso_usage[] = {
{
BIT(EMC_USER_DC),
80, iso_share_calc_t114_lpddr3_dc
},
{
BIT(EMC_USER_DC) | BIT(EMC_USER_VI),
45, iso_share_calc_t114_lpddr3_default
},
{
BIT(EMC_USER_DC) | BIT(EMC_USER_MSENC),
50, iso_share_calc_t114_lpddr3_default
},
{
BIT(EMC_USER_DC) | BIT(EMC_USER_3D),
50, iso_share_calc_t114_lpddr3_default
},
{
BIT(EMC_USER_DC) | BIT(EMC_USER_VDE),
45, iso_share_calc_t114_lpddr3_default
},
};
static struct emc_iso_usage tegra11_ddr3_emc_iso_usage[] = {
{
BIT(EMC_USER_DC),
80, iso_share_calc_t114_ddr3_dc
},
{
BIT(EMC_USER_DC) | BIT(EMC_USER_VI),
45, iso_share_calc_t114_ddr3_default
},
{
BIT(EMC_USER_DC) | BIT(EMC_USER_MSENC),
50, iso_share_calc_t114_ddr3_default
},
{
BIT(EMC_USER_DC) | BIT(EMC_USER_3D),
50, iso_share_calc_t114_ddr3_default
},
{
BIT(EMC_USER_DC) | BIT(EMC_USER_VDE),
45, iso_share_calc_t114_ddr3_default
},
};
#define KHZ 1000
#define PLL_C_DIRECT_FLOOR 333500000
#define EMC_STATUS_UPDATE_TIMEOUT 100
#define TEGRA_EMC_TABLE_MAX_SIZE 16
enum {
DLL_CHANGE_NONE = 0,
DLL_CHANGE_ON,
DLL_CHANGE_OFF,
};
#define EMC_CLK_DIV_SHIFT 0
#define EMC_CLK_DIV_MASK (0xFF << EMC_CLK_DIV_SHIFT)
#define EMC_CLK_SOURCE_SHIFT 29
#define EMC_CLK_SOURCE_MASK (0x7 << EMC_CLK_SOURCE_SHIFT)
#define EMC_CLK_LOW_JITTER_ENABLE (0x1 << 31)
#define EMC_CLK_MC_SAME_FREQ (0x1 << 16)
/* FIXME: actual Tegar11 list */
#define BURST_REG_LIST \
DEFINE_REG(TEGRA_EMC_BASE, EMC_RC), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_RFC), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_RFC_SLR), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_RAS), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_RP), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_R2W), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_W2R), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_R2P), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_W2P), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_RD_RCD), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_WR_RCD), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_RRD), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_REXT), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_WEXT), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_WDV), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_WDV_MASK), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_IBDLY), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_PUTERM_EXTRA), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_CDB_CNTL_2), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_QRST), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_RDV_MASK), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_REFRESH), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_BURST_REFRESH_NUM), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_PRE_REFRESH_REQ_CNT), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_PDEX2WR), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_PDEX2RD), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_PCHG2PDEN), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_ACT2PDEN), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_AR2PDEN), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_RW2PDEN), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_TXSR), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_TXSRDLL), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_TCKE), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_TCKESR), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_TPD), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_TFAW), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_TRPAB), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_TCLKSTABLE), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_TCLKSTOP), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_TREFBW), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_QUSE_EXTRA), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_ODT_WRITE), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_ODT_READ), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_FBIO_CFG5), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_CFG_DIG_DLL), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_CFG_DIG_DLL_PERIOD), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_DLL_XFORM_DQS4), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_DLL_XFORM_DQS5), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_DLL_XFORM_DQS6), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_DLL_XFORM_DQS7), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_DLL_XFORM_QUSE4), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_DLL_XFORM_QUSE5), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_DLL_XFORM_QUSE6), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_DLL_XFORM_QUSE7), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_DLI_TRIM_TXDQS4), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_DLI_TRIM_TXDQS5), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_DLI_TRIM_TXDQS6), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_DLI_TRIM_TXDQS7), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_XM2CMDPADCTRL), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_XM2CMDPADCTRL4), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_XM2DQSPADCTRL2), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_XM2DQPADCTRL2), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_XM2CLKPADCTRL), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_XM2COMPPADCTRL), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_XM2VTTGENPADCTRL), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_XM2VTTGENPADCTRL2), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_DSR_VTTGEN_DRV), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_TXDSRVTTGEN), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_FBIO_SPARE), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_CTT_TERM_CTRL), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_ZCAL_INTERVAL), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_ZCAL_WAIT_CNT), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_MRS_WAIT_CNT), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_MRS_WAIT_CNT2), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_AUTO_CAL_CONFIG2), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_AUTO_CAL_CONFIG3), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_CTT), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_CTT_DURATION), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_DYN_SELF_REF_CONTROL), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_CA_TRAINING_TIMING_CNTL1), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_CA_TRAINING_TIMING_CNTL2), \
\
DEFINE_REG(TEGRA_MC_BASE, MC_EMEM_ARB_CFG), \
DEFINE_REG(TEGRA_MC_BASE, MC_EMEM_ARB_OUTSTANDING_REQ), \
DEFINE_REG(TEGRA_MC_BASE, MC_EMEM_ARB_TIMING_RCD), \
DEFINE_REG(TEGRA_MC_BASE, MC_EMEM_ARB_TIMING_RP), \
DEFINE_REG(TEGRA_MC_BASE, MC_EMEM_ARB_TIMING_RC), \
DEFINE_REG(TEGRA_MC_BASE, MC_EMEM_ARB_TIMING_RAS), \
DEFINE_REG(TEGRA_MC_BASE, MC_EMEM_ARB_TIMING_FAW), \
DEFINE_REG(TEGRA_MC_BASE, MC_EMEM_ARB_TIMING_RRD), \
DEFINE_REG(TEGRA_MC_BASE, MC_EMEM_ARB_TIMING_RAP2PRE), \
DEFINE_REG(TEGRA_MC_BASE, MC_EMEM_ARB_TIMING_WAP2PRE), \
DEFINE_REG(TEGRA_MC_BASE, MC_EMEM_ARB_TIMING_R2R), \
DEFINE_REG(TEGRA_MC_BASE, MC_EMEM_ARB_TIMING_W2W), \
DEFINE_REG(TEGRA_MC_BASE, MC_EMEM_ARB_TIMING_R2W), \
DEFINE_REG(TEGRA_MC_BASE, MC_EMEM_ARB_TIMING_W2R), \
DEFINE_REG(TEGRA_MC_BASE, MC_EMEM_ARB_DA_TURNS), \
DEFINE_REG(TEGRA_MC_BASE, MC_EMEM_ARB_DA_COVERS), \
DEFINE_REG(TEGRA_MC_BASE, MC_EMEM_ARB_MISC0), \
DEFINE_REG(TEGRA_MC_BASE, MC_EMEM_ARB_RING1_THROTTLE), \
DEFINE_REG(TEGRA_EMC_BASE, EMC_SEL_DPD_CTRL),
#define BURST_UP_DOWN_REG_LIST \
DEFINE_REG(TEGRA_MC_BASE, MC_PTSA_GRANT_DECREMENT), \
DEFINE_REG(TEGRA_MC_BASE, MC_LATENCY_ALLOWANCE_G2_0), \
DEFINE_REG(TEGRA_MC_BASE, MC_LATENCY_ALLOWANCE_G2_1), \
DEFINE_REG(TEGRA_MC_BASE, MC_LATENCY_ALLOWANCE_NV_0), \
DEFINE_REG(TEGRA_MC_BASE, MC_LATENCY_ALLOWANCE_NV2_0), \
DEFINE_REG(TEGRA_MC_BASE, MC_LATENCY_ALLOWANCE_NV_2), \
DEFINE_REG(TEGRA_MC_BASE, MC_LATENCY_ALLOWANCE_NV_1), \
DEFINE_REG(TEGRA_MC_BASE, MC_LATENCY_ALLOWANCE_NV2_1), \
DEFINE_REG(TEGRA_MC_BASE, MC_LATENCY_ALLOWANCE_NV_3), \
DEFINE_REG(TEGRA_MC_BASE, MC_LATENCY_ALLOWANCE_EPP_0), \
DEFINE_REG(TEGRA_MC_BASE, MC_LATENCY_ALLOWANCE_EPP_1),
#define EMC_TRIMMERS_REG_LIST \
DEFINE_REG(0, EMC_CDB_CNTL_1), \
DEFINE_REG(0, EMC_FBIO_CFG6), \
DEFINE_REG(0, EMC_QUSE), \
DEFINE_REG(0, EMC_EINPUT), \
DEFINE_REG(0, EMC_EINPUT_DURATION), \
DEFINE_REG(0, EMC_DLL_XFORM_DQS0), \
DEFINE_REG(0, EMC_QSAFE), \
DEFINE_REG(0, EMC_DLL_XFORM_QUSE0), \
DEFINE_REG(0, EMC_RDV), \
DEFINE_REG(0, EMC_XM2DQSPADCTRL4), \
DEFINE_REG(0, EMC_XM2DQSPADCTRL3), \
DEFINE_REG(0, EMC_DLL_XFORM_DQ0), \
DEFINE_REG(0, EMC_AUTO_CAL_CONFIG), \
DEFINE_REG(0, EMC_DLL_XFORM_ADDR0), \
DEFINE_REG(0, EMC_XM2CLKPADCTRL2), \
DEFINE_REG(0, EMC_DLI_TRIM_TXDQS0), \
DEFINE_REG(0, EMC_DLL_XFORM_ADDR1), \
DEFINE_REG(0, EMC_DLL_XFORM_ADDR2), \
DEFINE_REG(0, EMC_DLL_XFORM_DQS1), \
DEFINE_REG(0, EMC_DLL_XFORM_DQS2), \
DEFINE_REG(0, EMC_DLL_XFORM_DQS3), \
DEFINE_REG(0, EMC_DLL_XFORM_DQ1), \
DEFINE_REG(0, EMC_DLL_XFORM_DQ2), \
DEFINE_REG(0, EMC_DLL_XFORM_DQ3), \
DEFINE_REG(0, EMC_DLI_TRIM_TXDQS1), \
DEFINE_REG(0, EMC_DLI_TRIM_TXDQS2), \
DEFINE_REG(0, EMC_DLI_TRIM_TXDQS3), \
DEFINE_REG(0, EMC_DLL_XFORM_QUSE1), \
DEFINE_REG(0, EMC_DLL_XFORM_QUSE2), \
DEFINE_REG(0, EMC_DLL_XFORM_QUSE3),
#define DEFINE_REG(base, reg) ((base) ? (IO_ADDRESS((base)) + (reg)) : 0)
static const void __iomem *burst_reg_addr[TEGRA11_EMC_MAX_NUM_REGS] = {
BURST_REG_LIST
};
#ifndef EMULATE_CLOCK_SWITCH
static const void __iomem *burst_up_down_reg_addr[TEGRA11_EMC_MAX_NUM_REGS] = {
BURST_UP_DOWN_REG_LIST
};
#endif
#undef DEFINE_REG
#define DEFINE_REG(base, reg) (reg)
#ifndef EMULATE_CLOCK_SWITCH
static const u32 emc_trimmer_offs[TEGRA11_EMC_MAX_NUM_REGS] = {
EMC_TRIMMERS_REG_LIST
};
#endif
#undef DEFINE_REG
#define DEFINE_REG(base, reg) reg##_INDEX
enum {
BURST_REG_LIST
};
#undef DEFINE_REG
#define DEFINE_REG(base, reg) reg##_TRIM_INDEX
enum {
EMC_TRIMMERS_REG_LIST
};
#undef DEFINE_REG
struct emc_sel {
struct clk *input;
u32 value;
unsigned long input_rate;
};
static struct emc_sel tegra_emc_clk_sel[TEGRA_EMC_TABLE_MAX_SIZE];
static struct tegra11_emc_table start_timing;
static const struct tegra11_emc_table *emc_timing;
static ktime_t clkchange_time;
static int clkchange_delay = 100;
static const u32 *dram_to_soc_bit_map;
static const struct tegra11_emc_table *tegra_emc_table;
static int tegra_emc_table_size;
static u32 dram_dev_num;
static u32 dram_type = -1;
static struct clk *emc;
static struct {
cputime64_t time_at_clock[TEGRA_EMC_TABLE_MAX_SIZE];
int last_sel;
u64 last_update;
u64 clkchange_count;
spinlock_t spinlock;
} emc_stats;
static DEFINE_SPINLOCK(emc_access_lock);
static void __iomem *emc_base = IO_ADDRESS(TEGRA_EMC_BASE);
static void __iomem *emc0_base = IO_ADDRESS(TEGRA_EMC0_BASE);
static void __iomem *emc1_base = IO_ADDRESS(TEGRA_EMC1_BASE);
static void __iomem *mc_base = IO_ADDRESS(TEGRA_MC_BASE);
static void __iomem *clk_base = IO_ADDRESS(TEGRA_CLK_RESET_BASE);
static inline void emc_writel(u32 val, unsigned long addr)
{
writel(val, (u32)emc_base + addr);
}
static inline void emc0_writel(u32 val, unsigned long addr)
{
writel(val, (u32)emc0_base + addr);
}
static inline void emc1_writel(u32 val, unsigned long addr)
{
writel(val, (u32)emc1_base + addr);
}
static inline u32 emc_readl(unsigned long addr)
{
return readl((u32)emc_base + addr);
}
static inline void mc_writel(u32 val, unsigned long addr)
{
writel(val, (u32)mc_base + addr);
}
static inline u32 mc_readl(unsigned long addr)
{
return readl((u32)mc_base + addr);
}
static inline void ccfifo_writel(u32 val, unsigned long addr)
{
writel(val, (u32)emc_base + EMC_CCFIFO_DATA);
writel(addr, (u32)emc_base + EMC_CCFIFO_ADDR);
}
static int last_round_idx;
static inline int get_start_idx(unsigned long rate)
{
if (tegra_emc_table[last_round_idx].rate == rate)
return last_round_idx;
return 0;
}
static void emc_last_stats_update(int last_sel)
{
unsigned long flags;
u64 cur_jiffies = get_jiffies_64();
spin_lock_irqsave(&emc_stats.spinlock, flags);
if (emc_stats.last_sel < TEGRA_EMC_TABLE_MAX_SIZE)
emc_stats.time_at_clock[emc_stats.last_sel] =
emc_stats.time_at_clock[emc_stats.last_sel] +
(cur_jiffies - emc_stats.last_update);
emc_stats.last_update = cur_jiffies;
if (last_sel < TEGRA_EMC_TABLE_MAX_SIZE) {
emc_stats.clkchange_count++;
emc_stats.last_sel = last_sel;
}
spin_unlock_irqrestore(&emc_stats.spinlock, flags);
}
static int wait_for_update(u32 status_reg, u32 bit_mask, bool updated_state)
{
int i;
for (i = 0; i < EMC_STATUS_UPDATE_TIMEOUT; i++) {
if (!!(emc_readl(status_reg) & bit_mask) == updated_state)
return 0;
udelay(1);
}
return -ETIMEDOUT;
}
static inline void emc_timing_update(void)
{
int err;
emc_writel(0x1, EMC_TIMING_CONTROL);
err = wait_for_update(EMC_STATUS,
EMC_STATUS_TIMING_UPDATE_STALLED, false);
if (err) {
pr_err("%s: timing update error: %d", __func__, err);
BUG();
}
}
static inline void auto_cal_disable(void)
{
int err;
emc_writel(0, EMC_AUTO_CAL_INTERVAL);
err = wait_for_update(EMC_AUTO_CAL_STATUS,
EMC_AUTO_CAL_STATUS_ACTIVE, false);
if (err) {
pr_err("%s: disable auto-cal error: %d", __func__, err);
BUG();
}
}
static inline bool dqs_preset(const struct tegra11_emc_table *next_timing,
const struct tegra11_emc_table *last_timing)
{
bool ret = false;
#define DQS_SET(reg, bit) \
do { \
if ((next_timing->burst_regs[EMC_##reg##_INDEX] & \
EMC_##reg##_##bit##_ENABLE) && \
(!(last_timing->burst_regs[EMC_##reg##_INDEX] & \
EMC_##reg##_##bit##_ENABLE))) { \
emc_writel(last_timing->burst_regs[EMC_##reg##_INDEX] \
| EMC_##reg##_##bit##_ENABLE, EMC_##reg); \
ret = true; \
} \
} while (0)
#define DQS_SET_TRIM(reg, bit, ch) \
do { \
if ((next_timing->emc_trimmers_##ch[EMC_##reg##_TRIM_INDEX] \
& EMC_##reg##_##bit##_ENABLE) && \
(!(last_timing->emc_trimmers_##ch[EMC_##reg##_TRIM_INDEX] \
& EMC_##reg##_##bit##_ENABLE))) { \
emc##ch##_writel(last_timing->emc_trimmers_##ch[EMC_##reg##_TRIM_INDEX] \
| EMC_##reg##_##bit##_ENABLE, EMC_##reg); \
ret = true; \
} \
} while (0)
DQS_SET(XM2DQSPADCTRL2, VREF);
return ret;
}
static inline void overwrite_mrs_wait_cnt(
const struct tegra11_emc_table *next_timing,
bool zcal_long)
{
u32 reg;
u32 cnt = 512;
/* For ddr3 when DLL is re-started: overwrite EMC DFS table settings
for MRS_WAIT_LONG with maximum of MRS_WAIT_SHORT settings and
expected operation length. Reduce the latter by the overlapping
zq-calibration, if any */
if (zcal_long)
cnt -= dram_dev_num * 256;
reg = (next_timing->burst_regs[EMC_MRS_WAIT_CNT_INDEX] &
EMC_MRS_WAIT_CNT_SHORT_WAIT_MASK) >>
EMC_MRS_WAIT_CNT_SHORT_WAIT_SHIFT;
if (cnt < reg)
cnt = reg;
reg = (next_timing->burst_regs[EMC_MRS_WAIT_CNT_INDEX] &
(~EMC_MRS_WAIT_CNT_LONG_WAIT_MASK));
reg |= (cnt << EMC_MRS_WAIT_CNT_LONG_WAIT_SHIFT) &
EMC_MRS_WAIT_CNT_LONG_WAIT_MASK;
emc_writel(reg, EMC_MRS_WAIT_CNT);
}
static inline int get_dll_change(const struct tegra11_emc_table *next_timing,
const struct tegra11_emc_table *last_timing)
{
bool next_dll_enabled = !(next_timing->emc_mode_1 & 0x1);
bool last_dll_enabled = !(last_timing->emc_mode_1 & 0x1);
if (next_dll_enabled == last_dll_enabled)
return DLL_CHANGE_NONE;
else if (next_dll_enabled)
return DLL_CHANGE_ON;
else
return DLL_CHANGE_OFF;
}
static inline void set_dram_mode(const struct tegra11_emc_table *next_timing,
const struct tegra11_emc_table *last_timing,
int dll_change)
{
if (dram_type == DRAM_TYPE_DDR3) {
/* first mode_1, then mode_2, then mode_reset*/
if (next_timing->emc_mode_1 != last_timing->emc_mode_1)
ccfifo_writel(next_timing->emc_mode_1, EMC_EMRS);
if (next_timing->emc_mode_2 != last_timing->emc_mode_2)
ccfifo_writel(next_timing->emc_mode_2, EMC_EMRS2);
if ((next_timing->emc_mode_reset !=
last_timing->emc_mode_reset) ||
(dll_change == DLL_CHANGE_ON)) {
u32 reg = next_timing->emc_mode_reset &
(~EMC_MODE_SET_DLL_RESET);
if (dll_change == DLL_CHANGE_ON) {
reg |= EMC_MODE_SET_DLL_RESET;
reg |= EMC_MODE_SET_LONG_CNT;
}
ccfifo_writel(reg, EMC_MRS);
}
} else {
/* first mode_2, then mode_1; mode_reset is not applicable */
if (next_timing->emc_mode_2 != last_timing->emc_mode_2)
ccfifo_writel(next_timing->emc_mode_2, EMC_MRW2);
if (next_timing->emc_mode_1 != last_timing->emc_mode_1)
ccfifo_writel(next_timing->emc_mode_1, EMC_MRW);
if (next_timing->emc_mode_4 != last_timing->emc_mode_4)
ccfifo_writel(next_timing->emc_mode_4, EMC_MRW4);
}
}
static inline void do_clock_change(u32 clk_setting)
{
int err;
mc_readl(MC_EMEM_ADR_CFG); /* completes prev writes */
writel(clk_setting, (u32)clk_base + emc->reg);
readl((u32)clk_base + emc->reg);/* completes prev write */
err = wait_for_update(EMC_INTSTATUS,
EMC_INTSTATUS_CLKCHANGE_COMPLETE, true);
if (err) {
pr_err("%s: clock change completion error: %d", __func__, err);
BUG();
}
}
static noinline void emc_set_clock(const struct tegra11_emc_table *next_timing,
const struct tegra11_emc_table *last_timing,
u32 clk_setting)
{
#ifndef EMULATE_CLOCK_SWITCH
int i, dll_change, pre_wait;
bool dyn_sref_enabled, zcal_long;
u32 emc_cfg_reg = emc_readl(EMC_CFG);
dyn_sref_enabled = emc_cfg_reg & EMC_CFG_DYN_SREF_ENABLE;
dll_change = get_dll_change(next_timing, last_timing);
zcal_long = (next_timing->burst_regs[EMC_ZCAL_INTERVAL_INDEX] != 0) &&
(last_timing->burst_regs[EMC_ZCAL_INTERVAL_INDEX] == 0);
/* FIXME: remove steps enumeration below? */
/* 1. clear clkchange_complete interrupts */
emc_writel(EMC_INTSTATUS_CLKCHANGE_COMPLETE, EMC_INTSTATUS);
/* 2. disable dynamic self-refresh and preset dqs vref, then wait for
possible self-refresh entry/exit and/or dqs vref settled - waiting
before the clock change decreases worst case change stall time */
pre_wait = 0;
if (dyn_sref_enabled) {
emc_cfg_reg &= ~EMC_CFG_DYN_SREF_ENABLE;
emc_writel(emc_cfg_reg, EMC_CFG);
pre_wait = 5; /* 5us+ for self-refresh entry/exit */
}
/* 2.5 check dq/dqs vref delay */
if (dqs_preset(next_timing, last_timing)) {
if (pre_wait < 3)
pre_wait = 3; /* 3us+ for dqs vref settled */
}
if (pre_wait) {
emc_timing_update();
udelay(pre_wait);
}
/* 3. disable auto-cal if vref mode is switching - removed */
/* 4. program burst shadow registers */
for (i = 0; i < next_timing->burst_regs_num; i++) {
if (!burst_reg_addr[i])
continue;
__raw_writel(next_timing->burst_regs[i], burst_reg_addr[i]);
}
for (i = 0; i < next_timing->emc_trimmers_num; i++) {
__raw_writel(next_timing->emc_trimmers_0[i],
(u32)emc0_base + emc_trimmer_offs[i]);
__raw_writel(next_timing->emc_trimmers_1[i],
(u32)emc1_base + emc_trimmer_offs[i]);
}
emc_cfg_reg &= ~EMC_CFG_UPDATE_MASK;
emc_cfg_reg |= next_timing->emc_cfg & EMC_CFG_UPDATE_MASK;
emc_writel(emc_cfg_reg, EMC_CFG);
wmb();
barrier();
/* 4.1 On ddr3 when DLL is re-started predict MRS long wait count and
overwrite DFS table setting */
if ((dram_type == DRAM_TYPE_DDR3) && (dll_change == DLL_CHANGE_ON))
overwrite_mrs_wait_cnt(next_timing, zcal_long);
/* 5.2 disable auto-refresh to save time after clock change */
ccfifo_writel(EMC_REFCTRL_DISABLE_ALL(dram_dev_num), EMC_REFCTRL);
/* 6. turn Off dll and enter self-refresh on DDR3 */
if (dram_type == DRAM_TYPE_DDR3) {
if (dll_change == DLL_CHANGE_OFF)
ccfifo_writel(next_timing->emc_mode_1, EMC_EMRS);
ccfifo_writel(DRAM_BROADCAST(dram_dev_num) |
EMC_SELF_REF_CMD_ENABLED, EMC_SELF_REF);
}
/* 7. flow control marker 2 */
ccfifo_writel(1, EMC_STALL_THEN_EXE_AFTER_CLKCHANGE);
/* 8. exit self-refresh on DDR3 */
if (dram_type == DRAM_TYPE_DDR3)
ccfifo_writel(DRAM_BROADCAST(dram_dev_num), EMC_SELF_REF);
/* 8.1 re-enable auto-refresh */
ccfifo_writel(EMC_REFCTRL_ENABLE_ALL(dram_dev_num), EMC_REFCTRL);
/* 9. set dram mode registers */
set_dram_mode(next_timing, last_timing, dll_change);
/* 10. issue zcal command if turning zcal On */
if (zcal_long) {
ccfifo_writel(EMC_ZQ_CAL_LONG_CMD_DEV0, EMC_ZQ_CAL);
if (dram_dev_num > 1)
ccfifo_writel(EMC_ZQ_CAL_LONG_CMD_DEV1, EMC_ZQ_CAL);
}
/* 10.1 dummy write to RO register to remove stall after change */
ccfifo_writel(0, EMC_CCFIFO_STATUS);
/* 11.5 program burst_up_down registers if emc rate is going down */
if (next_timing->rate < last_timing->rate) {
for (i = 0; i < next_timing->burst_up_down_regs_num; i++)
__raw_writel(next_timing->burst_up_down_regs[i],
burst_up_down_reg_addr[i]);
wmb();
}
/* 12-14. read any MC register to ensure the programming is done
change EMC clock source register wait for clk change completion */
do_clock_change(clk_setting);
/* 14.1 re-enable auto-refresh - moved to ccfifo in 8.1 */
/* 14.2 program burst_up_down registers if emc rate is going up */
if (next_timing->rate > last_timing->rate) {
for (i = 0; i < next_timing->burst_up_down_regs_num; i++)
__raw_writel(next_timing->burst_up_down_regs[i],
burst_up_down_reg_addr[i]);
wmb();
}
/* 15. set auto-cal interval */
if (next_timing->rev >= 0x42)
emc_writel(next_timing->emc_acal_interval,
EMC_AUTO_CAL_INTERVAL);
/* 16. restore dynamic self-refresh */
if (next_timing->emc_cfg & EMC_CFG_DYN_SREF_ENABLE) {
emc_cfg_reg |= EMC_CFG_DYN_SREF_ENABLE;
emc_writel(emc_cfg_reg, EMC_CFG);
}
/* 17. set zcal wait count */
emc_writel(next_timing->emc_zcal_cnt_long, EMC_ZCAL_WAIT_CNT);
/* 18. update restored timing */
udelay(2);
emc_timing_update();
#else
/* FIXME: implement */
pr_info("tegra11_emc: Configuring EMC rate %lu (setting: 0x%x)\n",
next_timing->rate, clk_setting);
#endif
}
static inline void emc_get_timing(struct tegra11_emc_table *timing)
{
int i;
/* burst and trimmers updates depends on previous state; burst_up_down
are stateless */
for (i = 0; i < timing->burst_regs_num; i++) {
if (burst_reg_addr[i])
timing->burst_regs[i] = __raw_readl(burst_reg_addr[i]);
else
timing->burst_regs[i] = 0;
}
for (i = 0; i < timing->emc_trimmers_num; i++) {
timing->emc_trimmers_0[i] =
__raw_readl((u32)emc0_base + emc_trimmer_offs[i]);
timing->emc_trimmers_1[i] =
__raw_readl((u32)emc1_base + emc_trimmer_offs[i]);
}
timing->emc_acal_interval = 0;
timing->emc_zcal_cnt_long = 0;
timing->emc_mode_reset = 0;
timing->emc_mode_1 = 0;
timing->emc_mode_2 = 0;
timing->emc_mode_4 = 0;
timing->emc_cfg = emc_readl(EMC_CFG);
timing->rate = clk_get_rate_locked(emc) / 1000;
}
/* The EMC registers have shadow registers. When the EMC clock is updated
* in the clock controller, the shadow registers are copied to the active
* registers, allowing glitchless memory bus frequency changes.
* This function updates the shadow registers for a new clock frequency,
* and relies on the clock lock on the emc clock to avoid races between
* multiple frequency changes. In addition access lock prevents concurrent
* access to EMC registers from reading MRR registers */
int tegra_emc_set_rate(unsigned long rate)
{
int i;
u32 clk_setting;
const struct tegra11_emc_table *last_timing;
unsigned long flags;
s64 last_change_delay;
if (!tegra_emc_table)
return -EINVAL;
/* Table entries specify rate in kHz */
rate = rate / 1000;
i = get_start_idx(rate);
for (; i < tegra_emc_table_size; i++) {
if (tegra_emc_clk_sel[i].input == NULL)
continue; /* invalid entry */
if (tegra_emc_table[i].rate == rate)
break;
}
if (i >= tegra_emc_table_size)
return -EINVAL;
if (!emc_timing) {
/* can not assume that boot timing matches dfs table even
if boot frequency matches one of the table nodes */
emc_get_timing(&start_timing);
last_timing = &start_timing;
}
else
last_timing = emc_timing;
clk_setting = tegra_emc_clk_sel[i].value;
last_change_delay = ktime_us_delta(ktime_get(), clkchange_time);
if ((last_change_delay >= 0) && (last_change_delay < clkchange_delay))
udelay(clkchange_delay - (int)last_change_delay);
spin_lock_irqsave(&emc_access_lock, flags);
emc_set_clock(&tegra_emc_table[i], last_timing, clk_setting);
clkchange_time = ktime_get();
emc_timing = &tegra_emc_table[i];
spin_unlock_irqrestore(&emc_access_lock, flags);
emc_last_stats_update(i);
pr_debug("%s: rate %lu setting 0x%x\n", __func__, rate, clk_setting);
return 0;
}
long tegra_emc_round_rate_updown(unsigned long rate, bool up)
{
int i;
unsigned long table_rate;
if (!tegra_emc_table)
return clk_get_rate_locked(emc); /* no table - no rate change */
if (!emc_enable)
return -EINVAL;
pr_debug("%s: %lu\n", __func__, rate);
/* Table entries specify rate in kHz */
rate = rate / 1000;
i = get_start_idx(rate);
for (; i < tegra_emc_table_size; i++) {
if (tegra_emc_clk_sel[i].input == NULL)
continue; /* invalid entry */
table_rate = tegra_emc_table[i].rate;
if (table_rate >= rate) {
if (!up && i && (table_rate > rate)) {
i--;
table_rate = tegra_emc_table[i].rate;
}
pr_debug("%s: using %lu\n", __func__, table_rate);
last_round_idx = i;
return table_rate * 1000;
}
}
return -EINVAL;
}
struct clk *tegra_emc_predict_parent(unsigned long rate, u32 *div_value)
{
int i;
if (!tegra_emc_table) {
if (rate == clk_get_rate_locked(emc)) {
*div_value = emc->div - 2;
return emc->parent;
}
return NULL;
}
pr_debug("%s: %lu\n", __func__, rate);
/* Table entries specify rate in kHz */
rate = rate / 1000;
i = get_start_idx(rate);
for (; i < tegra_emc_table_size; i++) {
if (tegra_emc_table[i].rate == rate) {
struct clk *p = tegra_emc_clk_sel[i].input;
if (p && (tegra_emc_clk_sel[i].input_rate ==
clk_get_rate(p))) {
*div_value = (tegra_emc_clk_sel[i].value &
EMC_CLK_DIV_MASK) >> EMC_CLK_DIV_SHIFT;
return p;
}
}
}
return NULL;
}
bool tegra_emc_is_parent_ready(unsigned long rate, struct clk **parent,
unsigned long *parent_rate, unsigned long *backup_rate)
{
int i;
struct clk *p = NULL;
unsigned long p_rate = 0;
if (!tegra_emc_table)
return true;
pr_debug("%s: %lu\n", __func__, rate);
/* Table entries specify rate in kHz */
rate = rate / 1000;
i = get_start_idx(rate);
for (; i < tegra_emc_table_size; i++) {
if (tegra_emc_table[i].rate == rate) {
p = tegra_emc_clk_sel[i].input;
if (!p)
continue; /* invalid entry */
p_rate = tegra_emc_clk_sel[i].input_rate;
if (p_rate == clk_get_rate(p))
return true;
break;
}
}
/* Table match not found - "non existing parent" is ready */
if (!p)
return true;
#ifdef CONFIG_TEGRA_PLLM_SCALED
/*
* Table match found, but parent is not ready - check if backup entry
* was found during initialization, and return the respective backup
* rate
*/
if (emc->shared_bus_backup.input &&
(emc->shared_bus_backup.input != p)) {
*parent = p;
*parent_rate = p_rate;
*backup_rate = emc->shared_bus_backup.bus_rate;
return false;
}
#else
/*
* Table match found, but parent is not ready - continue search
* for backup rate: min rate above requested that has different
* parent source (since only pll_c is scaled and may not be ready,
* any other parent can provide backup)
*/
*parent = p;
*parent_rate = p_rate;
for (i++; i < tegra_emc_table_size; i++) {
p = tegra_emc_clk_sel[i].input;
if (!p)
continue; /* invalid entry */
if (p != (*parent)) {
*backup_rate = tegra_emc_table[i].rate * 1000;
return false;
}
}
#endif
/* Parent is not ready, and no backup found */
*backup_rate = -EINVAL;
return false;
}
static inline const struct clk_mux_sel *get_emc_input(u32 val)
{
const struct clk_mux_sel *sel;
for (sel = emc->inputs; sel->input != NULL; sel++) {
if (sel->value == val)
break;
}
return sel;
}
static int find_matching_input(const struct tegra11_emc_table *table,
struct clk *pll_c, struct emc_sel *emc_clk_sel)
{
u32 div_value = (table->src_sel_reg & EMC_CLK_DIV_MASK) >>
EMC_CLK_DIV_SHIFT;
u32 src_value = (table->src_sel_reg & EMC_CLK_SOURCE_MASK) >>
EMC_CLK_SOURCE_SHIFT;
unsigned long input_rate = 0;
unsigned long table_rate = table->rate * 1000; /* table rate in kHz */
const struct clk_mux_sel *sel = get_emc_input(src_value);
#ifdef CONFIG_TEGRA_PLLM_SCALED
struct clk *scalable_pll = emc->parent; /* pll_m is a boot parent */
#else
struct clk *scalable_pll = pll_c;
#endif
pr_info_once("tegra: %s is selected as scalable EMC clock source\n",
scalable_pll->name);
if (div_value & 0x1) {
pr_warn("tegra: invalid odd divider for EMC rate %lu\n",
table_rate);
return -EINVAL;
}
if (!sel->input) {
pr_warn("tegra: no matching input found for EMC rate %lu\n",
table_rate);
return -EINVAL;
}
if (div_value && (table->src_sel_reg & EMC_CLK_LOW_JITTER_ENABLE)) {
pr_warn("tegra: invalid LJ path for EMC rate %lu\n",
table_rate);
return -EINVAL;
}
if (!(table->src_sel_reg & EMC_CLK_MC_SAME_FREQ) !=
!(MC_EMEM_ARB_MISC0_EMC_SAME_FREQ &
table->burst_regs[MC_EMEM_ARB_MISC0_INDEX])) {
pr_warn("tegra: ambiguous EMC to MC ratio for EMC rate %lu\n",
table_rate);
return -EINVAL;
}
#ifndef CONFIG_TEGRA_DUAL_CBUS
if (sel->input == pll_c) {
pr_warn("tegra: %s is cbus source: no EMC rate %lu support\n",
sel->input->name, table_rate);
return -EINVAL;
}
#endif
if (sel->input == scalable_pll) {
input_rate = table_rate * (1 + div_value / 2);
} else {
/* all other sources are fixed, must exactly match the rate */
input_rate = clk_get_rate(sel->input);
if (input_rate != (table_rate * (1 + div_value / 2))) {
pr_warn("tegra: EMC rate %lu does not match %s rate %lu\n",
table_rate, sel->input->name, input_rate);
return -EINVAL;
}
}
#ifdef CONFIG_TEGRA_PLLM_SCALED
if (sel->input == pll_c) {
/* maybe overwritten in a loop - end up at max rate
from pll_c */
emc->shared_bus_backup.input = pll_c;
emc->shared_bus_backup.bus_rate = table_rate;
}
#endif
/* Get ready emc clock selection settings for this table rate */
emc_clk_sel->input = sel->input;
emc_clk_sel->input_rate = input_rate;
emc_clk_sel->value = table->src_sel_reg;
return 0;
}
static void adjust_emc_dvfs_table(const struct tegra11_emc_table *table,
int table_size)
{
int i, j;
unsigned long rate;
for (i = 0; i < MAX_DVFS_FREQS; i++) {
int mv = emc->dvfs->millivolts[i];
if (!mv)
break;
/* For each dvfs voltage find maximum supported rate;
use 1MHz placeholder if not found */
for (rate = 1000, j = 0; j < table_size; j++) {
if (tegra_emc_clk_sel[j].input == NULL)
continue; /* invalid entry */
if ((mv >= table[j].emc_min_mv) &&
(rate < table[j].rate))
rate = table[j].rate;
}
/* Table entries specify rate in kHz */
emc->dvfs->freqs[i] = rate * 1000;
}
}
#ifdef CONFIG_TEGRA_PLLM_SCALED
/* When pll_m is scaled, pll_c must provide backup rate;
if not - remove rates that require pll_m scaling */
static int purge_emc_table(unsigned long max_rate)
{
int i;
int ret = 0;
if (emc->shared_bus_backup.input)
return ret;
pr_warn("tegra: selected pll_m scaling option but no backup source:\n");
pr_warn(" removed not supported entries from the table:\n");
/* made all entries with non matching rate invalid */
for (i = 0; i < tegra_emc_table_size; i++) {
struct emc_sel *sel = &tegra_emc_clk_sel[i];
if (sel->input) {
if (clk_get_rate(sel->input) != sel->input_rate) {
pr_warn(" EMC rate %lu\n",
tegra_emc_table[i].rate * 1000);
sel->input = NULL;
sel->input_rate = 0;
sel->value = 0;
if (max_rate == tegra_emc_table[i].rate)
ret = -EINVAL;
}
}
}
return ret;
}
#else
/* When pll_m is fixed @ max EMC rate, it always provides backup for pll_c */
#define purge_emc_table(max_rate) (0)
#endif
#ifdef CONFIG_OF
static struct device_node *tegra_emc_ramcode_devnode(struct device_node *np)
{
struct device_node *iter;
u32 reg;
for_each_child_of_node(np, iter) {
if (of_property_read_u32(iter, "nvidia,ram-code", &reg))
continue;
#if defined(CONFIG_MACH_TEGRATAB) || defined(CONFIG_MACH_TEGRANOTE7C)
{
struct board_info board_info;
tegra_get_board_info(&board_info);
if (board_info.board_id == BOARD_P1640 &&
board_info.fab >= BOARD_FAB_A04) {
if (reg == tegra_bct_strapping)
return of_node_get(iter);
} else if (board_info.board_id == BOARD_P1640) {
/* force select ram strapping 0x0 */
if (reg == 0x0)
return of_node_get(iter);
} else if (board_info.board_id == BOARD_P1988) {
/*
* RAM_CODE[1:0] = 0x00 -> Micron DDR3L 1GB
* RAM_CODE[1:0] = 0x01 -> Hynix DDR3L 1GB
*/
if (reg == tegra_bct_strapping)
return of_node_get(iter);
}
}
#else
if (reg == tegra_bct_strapping)
return of_node_get(iter);
#endif /* CONFIG_MACH_TEGRATAB */
}
return NULL;
}
static struct tegra11_emc_pdata *tegra_emc_dt_parse_pdata(
struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct device_node *tnp, *iter;
struct tegra11_emc_pdata *pdata;
int ret, i, num_tables;
if (!np)
return NULL;
if (of_find_property(np, "nvidia,use-ram-code", NULL)) {
tnp = tegra_emc_ramcode_devnode(np);
if (!tnp)
dev_warn(&pdev->dev,
"can't find emc table for ram-code 0x%02x\n",
tegra_bct_strapping);
} else
tnp = of_node_get(np);
if (!tnp)
return NULL;
num_tables = 0;
for_each_child_of_node(tnp, iter)
if (of_device_is_compatible(iter, "nvidia,tegra11-emc-table"))
num_tables++;
if (!num_tables) {
pdata = NULL;
goto out;
}
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
pdata->tables = devm_kzalloc(&pdev->dev,
sizeof(*pdata->tables) * num_tables,
GFP_KERNEL);
i = 0;
for_each_child_of_node(tnp, iter) {
u32 u;
const char *source_name;
ret = of_property_read_u32(iter, "nvidia,revision", &u);
if (ret) {
dev_err(&pdev->dev, "no revision in %s\n",
iter->full_name);
continue;
}
pdata->tables[i].rev = u;
ret = of_property_read_u32(iter, "clock-frequency", &u);
if (ret) {
dev_err(&pdev->dev, "no clock-frequency in %s\n",
iter->full_name);
continue;
}
pdata->tables[i].rate = u;
ret = of_property_read_u32(iter, "nvidia,emc-min-mv", &u);
if (ret) {
dev_err(&pdev->dev, "no emc-min-mv in %s\n",
iter->full_name);
continue;
}
pdata->tables[i].emc_min_mv = u;
ret = of_property_read_string(iter,
"nvidia,source", &source_name);
if (ret) {
dev_err(&pdev->dev, "no source name in %s\n",
iter->full_name);
continue;
}
pdata->tables[i].src_name = source_name;
ret = of_property_read_u32(iter, "nvidia,src-sel-reg", &u);
if (ret) {
dev_err(&pdev->dev, "no src-sel-reg in %s\n",
iter->full_name);
continue;
}
pdata->tables[i].src_sel_reg = u;
ret = of_property_read_u32(iter, "nvidia,burst-regs-num", &u);
if (ret) {
dev_err(&pdev->dev, "no burst-regs-num in %s\n",
iter->full_name);
continue;
}
pdata->tables[i].burst_regs_num = u;
ret = of_property_read_u32(iter, "nvidia,emc-trimmers-num", &u);
if (ret) {
dev_err(&pdev->dev, "no emc-trimmers-num in %s\n",
iter->full_name);
continue;
}
pdata->tables[i].emc_trimmers_num = u;
ret = of_property_read_u32(iter,
"nvidia,burst-up-down-regs-num", &u);
if (ret) {
dev_err(&pdev->dev, "no burst-up-down-regs-num in %s\n",
iter->full_name);
continue;
}
pdata->tables[i].burst_up_down_regs_num = u;
ret = of_property_read_u32_array(iter, "nvidia,emc-registers",
pdata->tables[i].burst_regs,
pdata->tables[i].burst_regs_num);
if (ret) {
dev_err(&pdev->dev,
"malformed emc-registers property in %s\n",
iter->full_name);
continue;
}
ret = of_property_read_u32_array(iter, "nvidia,emc-trimmers-0",
pdata->tables[i].emc_trimmers_0,
pdata->tables[i].emc_trimmers_num);
if (ret) {
dev_err(&pdev->dev,
"malformed emc-trimmers-0 property in %s\n",
iter->full_name);
continue;
}
ret = of_property_read_u32_array(iter, "nvidia,emc-trimmers-1",
pdata->tables[i].emc_trimmers_1,
pdata->tables[i].emc_trimmers_num);
if (ret) {
dev_err(&pdev->dev,
"malformed emc-trimmers-1 property in %s\n",
iter->full_name);
continue;
}
ret = of_property_read_u32_array(iter,
"nvidia,emc-burst-up-down-regs",
pdata->tables[i].burst_up_down_regs,
pdata->tables[i].burst_up_down_regs_num);
if (ret) {
dev_err(&pdev->dev,
"malformed emc-burst-up-down-regs property in %s\n",
iter->full_name);
continue;
}
ret = of_property_read_u32(iter, "nvidia,emc-zcal-cnt-long",
&pdata->tables[i].emc_zcal_cnt_long);
if (ret) {
dev_err(&pdev->dev,
"malformed emc-zcal-cnt-long property in %s\n",
iter->full_name);
continue;
}
ret = of_property_read_u32(iter, "nvidia,emc-acal-interval",
&pdata->tables[i].emc_acal_interval);
if (ret) {
dev_err(&pdev->dev,
"malformed emc-acal-interval property in %s\n",
iter->full_name);
continue;
}
ret = of_property_read_u32(iter, "nvidia,emc-cfg",
&pdata->tables[i].emc_cfg);
if (ret) {
dev_err(&pdev->dev,
"malformed emc-cfg property in %s\n",
iter->full_name);
continue;
}
ret = of_property_read_u32(iter, "nvidia,emc-mode-reset",
&pdata->tables[i].emc_mode_reset);
if (ret) {
dev_err(&pdev->dev,
"malformed emc-mode-reset property in %s\n",
iter->full_name);
continue;
}
ret = of_property_read_u32(iter, "nvidia,emc-mode-1",
&pdata->tables[i].emc_mode_1);
if (ret) {
dev_err(&pdev->dev,
"malformed emc-mode-1 property in %s\n",
iter->full_name);
continue;
}
ret = of_property_read_u32(iter, "nvidia,emc-mode-2",
&pdata->tables[i].emc_mode_2);
if (ret) {
dev_err(&pdev->dev,
"malformed emc-mode-2 property in %s\n",
iter->full_name);
continue;
}
ret = of_property_read_u32(iter, "nvidia,emc-mode-4",
&pdata->tables[i].emc_mode_4);
if (ret) {
dev_err(&pdev->dev,
"malformed emc-mode-4 property in %s\n",
iter->full_name);
continue;
}
of_property_read_u32(iter, "nvidia,emc-clock-latency-change",
&pdata->tables[i].clock_change_latency);
i++;
}
pdata->num_tables = i;
out:
of_node_put(tnp);
return pdata;
}
#else
static struct tegra_emc_pdata *tegra_emc_dt_parse_pdata(
struct platform_device *pdev)
{
return NULL;
}
#endif
static int init_emc_table(const struct tegra11_emc_table *table, int table_size)
{
int i, mv;
u32 reg;
bool max_entry = false;
bool emc_max_dvfs_sel = get_emc_max_dvfs();
unsigned long boot_rate, max_rate;
struct clk *pll_c = tegra_get_clock_by_name("pll_c");
emc_stats.clkchange_count = 0;
spin_lock_init(&emc_stats.spinlock);
emc_stats.last_update = get_jiffies_64();
emc_stats.last_sel = TEGRA_EMC_TABLE_MAX_SIZE;
if ((dram_type != DRAM_TYPE_DDR3) && (dram_type != DRAM_TYPE_LPDDR2)) {
pr_err("tegra: not supported DRAM type %u\n", dram_type);
return -ENODATA;
}
if (emc->parent != tegra_get_clock_by_name("pll_m")) {
pr_err("tegra: boot parent %s is not supported by EMC DFS\n",
emc->parent->name);
return -ENODATA;
}
if (!table || !table_size) {
pr_err("tegra: EMC DFS table is empty\n");
return -ENODATA;
}
boot_rate = clk_get_rate(emc) / 1000;
max_rate = clk_get_rate(emc->parent) / 1000;
tegra_emc_table_size = min(table_size, TEGRA_EMC_TABLE_MAX_SIZE);
switch (table[0].rev) {
case 0x40:
case 0x41:
case 0x42:
start_timing.burst_regs_num = table[0].burst_regs_num;
start_timing.emc_trimmers_num = table[0].emc_trimmers_num;
break;
default:
pr_err("tegra: invalid EMC DFS table: unknown rev 0x%x\n",
table[0].rev);
return -ENODATA;
}
/* Match EMC source/divider settings with table entries */
for (i = 0; i < tegra_emc_table_size; i++) {
unsigned long table_rate = table[i].rate;
/* Skip "no-rate" entry, or entry violating ascending order */
if (!table_rate ||
(i && (table_rate <= table[i-1].rate)))
continue;
BUG_ON(table[i].rev != table[0].rev);
if (find_matching_input(&table[i], pll_c,
&tegra_emc_clk_sel[i]))
continue;
if (table_rate == boot_rate)
emc_stats.last_sel = i;
#ifdef CONFIG_ANDROID
if (get_androidboot_mode_charger() &&
(table_rate == boot_rate)) {
/* EMC max rate = bootloader emc rate */
max_entry = true;
break;
}
#endif
if (emc_max_dvfs_sel) {
/* EMC max rate = max table entry above boot pll_m */
if (table_rate >= max_rate) {
max_rate = table_rate;
max_entry = true;
}
} else if (table_rate == max_rate) {
/* EMC max rate = boot pll_m rate */
max_entry = true;
break;
}
}
/* Validate EMC rate and voltage limits */
if (!max_entry) {
pr_err("tegra: invalid EMC DFS table: entry for max rate"
" %lu kHz is not found\n", max_rate);
return -ENODATA;
}
tegra_emc_table = table;
/*
* Purge rates that cannot be reached because table does not specify
* proper backup source. If maximum rate was purged, fall back on boot
* pll_m rate as maximum limit. In any case propagate new maximum limit
* down stream to shared users, and check it against nominal voltage.
*/
if (purge_emc_table(max_rate))
max_rate = clk_get_rate(emc->parent) / 1000;
tegra_init_max_rate(emc, max_rate * 1000);
if (emc->dvfs) {
adjust_emc_dvfs_table(tegra_emc_table, tegra_emc_table_size);
mv = tegra_dvfs_predict_millivolts(emc, max_rate * 1000);
if ((mv <= 0) || (mv > emc->dvfs->max_millivolts)) {
tegra_emc_table = NULL;
pr_err("tegra: invalid EMC DFS table: maximum rate %lu"
" kHz does not match nominal voltage %d\n",
max_rate, emc->dvfs->max_millivolts);
return -ENODATA;
}
}
pr_info("tegra: validated EMC DFS table\n");
/* Configure clock change mode according to dram type */
reg = emc_readl(EMC_CFG_2) & (~EMC_CFG_2_MODE_MASK);
reg |= ((dram_type == DRAM_TYPE_LPDDR2) ? EMC_CFG_2_PD_MODE :
EMC_CFG_2_SREF_MODE) << EMC_CFG_2_MODE_SHIFT;
emc_writel(reg, EMC_CFG_2);
return 0;
}
static int __devinit tegra11_emc_probe(struct platform_device *pdev)
{
struct tegra11_emc_pdata *pdata;
struct resource *res;
if (tegra_emc_table)
return -EINVAL;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "missing register base\n");
return -ENOMEM;
}
pdata = pdev->dev.platform_data;
if (!pdata)
pdata = (struct tegra11_emc_pdata *)tegra_emc_dt_parse_pdata(pdev);
if (!pdata) {
dev_err(&pdev->dev, "missing platform data\n");
return -ENODATA;
}
return init_emc_table(pdata->tables, pdata->num_tables);
}
static struct of_device_id tegra11_emc_of_match[] __devinitdata = {
{ .compatible = "nvidia,tegra11-emc", },
{ },
};
static struct platform_driver tegra11_emc_driver = {
.driver = {
.name = "tegra-emc",
.owner = THIS_MODULE,
.of_match_table = tegra11_emc_of_match,
},
.probe = tegra11_emc_probe,
};
int __init tegra11_emc_init(void)
{
int ret = platform_driver_register(&tegra11_emc_driver);
if (!ret) {
if (dram_type == DRAM_TYPE_LPDDR2)
tegra_emc_iso_usage_table_init(
tegra11_lpddr3_emc_iso_usage,
ARRAY_SIZE(tegra11_lpddr3_emc_iso_usage));
else if (dram_type == DRAM_TYPE_DDR3)
tegra_emc_iso_usage_table_init(
tegra11_ddr3_emc_iso_usage,
ARRAY_SIZE(tegra11_ddr3_emc_iso_usage));
if (emc_enable) {
unsigned long rate = tegra_emc_round_rate_updown(
emc->boot_rate, false);
if (!IS_ERR_VALUE(rate))
tegra_clk_preset_emc_monitor(rate);
}
}
return ret;
}
void tegra_emc_timing_invalidate(void)
{
emc_timing = NULL;
}
void tegra_emc_dram_type_init(struct clk *c)
{
emc = c;
dram_type = (emc_readl(EMC_FBIO_CFG5) &
EMC_CFG5_TYPE_MASK) >> EMC_CFG5_TYPE_SHIFT;
dram_dev_num = (mc_readl(MC_EMEM_ADR_CFG) & 0x1) + 1; /* 2 dev max */
}
int tegra_emc_get_dram_type(void)
{
return dram_type;
}
static u32 soc_to_dram_bit_swap(u32 soc_val, u32 dram_mask, u32 dram_shift)
{
int bit;
u32 dram_val = 0;
/* tegra clocks definitions use shifted mask always */
if (!dram_to_soc_bit_map)
return soc_val & dram_mask;
for (bit = dram_shift; bit < 32; bit++) {
u32 dram_bit_mask = 0x1 << bit;
u32 soc_bit_mask = dram_to_soc_bit_map[bit];
if (!(dram_bit_mask & dram_mask))
break;
if (soc_bit_mask & soc_val)
dram_val |= dram_bit_mask;
}
return dram_val;
}
static int emc_read_mrr(int dev, int addr)
{
int ret;
u32 val, emc_cfg;
if (dram_type != DRAM_TYPE_LPDDR2)
return -ENODEV;
ret = wait_for_update(EMC_STATUS, EMC_STATUS_MRR_DIVLD, false);
if (ret)
return ret;
emc_cfg = emc_readl(EMC_CFG);
if (emc_cfg & EMC_CFG_DRAM_ACPD) {
emc_writel(emc_cfg & ~EMC_CFG_DRAM_ACPD, EMC_CFG);
emc_timing_update();
}
val = dev ? DRAM_DEV_SEL_1 : DRAM_DEV_SEL_0;
val |= (addr << EMC_MRR_MA_SHIFT) & EMC_MRR_MA_MASK;
emc_writel(val, EMC_MRR);
ret = wait_for_update(EMC_STATUS, EMC_STATUS_MRR_DIVLD, true);
if (emc_cfg & EMC_CFG_DRAM_ACPD) {
emc_writel(emc_cfg, EMC_CFG);
emc_timing_update();
}
if (ret)
return ret;
val = emc_readl(EMC_MRR) & EMC_MRR_DATA_MASK;
return val;
}
int tegra_emc_get_dram_temperature(void)
{
int mr4;
unsigned long flags;
spin_lock_irqsave(&emc_access_lock, flags);
mr4 = emc_read_mrr(0, 4);
if (IS_ERR_VALUE(mr4)) {
spin_unlock_irqrestore(&emc_access_lock, flags);
return mr4;
}
spin_unlock_irqrestore(&emc_access_lock, flags);
mr4 = soc_to_dram_bit_swap(
mr4, LPDDR2_MR4_TEMP_MASK, LPDDR2_MR4_TEMP_SHIFT);
return mr4;
}
static inline int bw_calc_get_freq_idx(u32 *bw_calc_freqs,
u32 freq_max_num, unsigned long bw)
{
int idx = 0;
if (!bw_calc_freqs)
return -EINVAL;
if (!freq_max_num)
return -EINVAL;
if (bw > bw_calc_freqs[freq_max_num-1] * KHZ)
idx = freq_max_num;
for (; idx < freq_max_num; idx++) {
u32 freq = bw_calc_freqs[idx] * KHZ;
if (bw < freq) {
if (idx)
idx--;
break;
} else if (bw == freq)
break;
}
return idx;
}
static u8 iso_share_calc_t114_lpddr3_default(unsigned long iso_bw)
{
int freq_idx = bw_calc_get_freq_idx(bw_calc_freqs_lpddr3,
ARRAY_SIZE(bw_calc_freqs_lpddr3), iso_bw);
return tegra11_lpddr3_emc_usage_share_default[freq_idx];
}
static u8 iso_share_calc_t114_lpddr3_dc(unsigned long iso_bw)
{
int freq_idx = bw_calc_get_freq_idx(bw_calc_freqs_lpddr3,
ARRAY_SIZE(bw_calc_freqs_lpddr3), iso_bw);
return tegra11_lpddr3_emc_usage_share_dc[freq_idx];
}
static u8 iso_share_calc_t114_ddr3_default(unsigned long iso_bw)
{
int freq_idx = bw_calc_get_freq_idx(bw_calc_freqs_ddr3,
ARRAY_SIZE(bw_calc_freqs_ddr3), iso_bw);
return tegra11_ddr3_emc_usage_share_default[freq_idx];
}
static u8 iso_share_calc_t114_ddr3_dc(unsigned long iso_bw)
{
int freq_idx = bw_calc_get_freq_idx(bw_calc_freqs_ddr3,
ARRAY_SIZE(bw_calc_freqs_ddr3), iso_bw);
return tegra11_ddr3_emc_usage_share_dc[freq_idx];
}
#ifdef CONFIG_DEBUG_FS
static struct dentry *emc_debugfs_root;
#define INFO_CALC_REV_OFFSET 1
#define INFO_SCRIPT_REV_OFFSET 2
#define INFO_FREQ_OFFSET 3
static int emc_table_info_show(struct seq_file *s, void *data)
{
int i;
const u32 *info;
u32 freq, calc_rev, script_rev;
const struct tegra11_emc_table *entry;
bool found = false;
if (!tegra_emc_table) {
seq_printf(s, "EMC DFS table is not installed\n");
return 0;
}
for (i = 0; i < tegra_emc_table_size; i++) {
entry = &tegra_emc_table[i];
info =
&entry->burst_up_down_regs[entry->burst_up_down_regs_num];
seq_printf(s, "%s: ", tegra_emc_clk_sel[i].input != NULL ?
"accepted" : "rejected");
/* system validation tag for metadata */
if (*info != 0x4E564441) {
seq_printf(s, "emc dvfs frequency %6lu\n", entry->rate);
continue;
}
found = true;
calc_rev = *(info + INFO_CALC_REV_OFFSET);
script_rev = *(info + INFO_SCRIPT_REV_OFFSET);
freq = *(info + INFO_FREQ_OFFSET);
seq_printf(s, "emc dvfs frequency %6u: ", freq);
seq_printf(s, "calc_rev: %02u.%02u.%02u.%02u ",
(calc_rev >> 24) & 0xff,
(calc_rev >> 16) & 0xff,
(calc_rev >> 8) & 0xff,
(calc_rev >> 0) & 0xff);
seq_printf(s, "script_rev: %02u.%02u.%02u.%02u\n",
(script_rev >> 24) & 0xff,
(script_rev >> 16) & 0xff,
(script_rev >> 8) & 0xff,
(script_rev >> 0) & 0xff);
}
if (!found)
seq_printf(s, "no metdata in EMC DFS table\n");
return 0;
}
static int emc_table_info_open(struct inode *inode, struct file *file)
{
return single_open(file, emc_table_info_show, inode->i_private);
}
static const struct file_operations emc_table_info_fops = {
.open = emc_table_info_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int emc_stats_show(struct seq_file *s, void *data)
{
int i;
emc_last_stats_update(TEGRA_EMC_TABLE_MAX_SIZE);
seq_printf(s, "%-10s %-10s \n", "rate kHz", "time");
for (i = 0; i < tegra_emc_table_size; i++) {
if (tegra_emc_clk_sel[i].input == NULL)
continue; /* invalid entry */
seq_printf(s, "%-10lu %-10llu \n", tegra_emc_table[i].rate,
cputime64_to_clock_t(emc_stats.time_at_clock[i]));
}
seq_printf(s, "%-15s %llu\n", "transitions:",
emc_stats.clkchange_count);
seq_printf(s, "%-15s %llu\n", "time-stamp:",
cputime64_to_clock_t(emc_stats.last_update));
return 0;
}
static int emc_stats_open(struct inode *inode, struct file *file)
{
return single_open(file, emc_stats_show, inode->i_private);
}
static const struct file_operations emc_stats_fops = {
.open = emc_stats_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int dram_temperature_get(void *data, u64 *val)
{
*val = tegra_emc_get_dram_temperature();
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(dram_temperature_fops, dram_temperature_get,
NULL, "%lld\n");
static int efficiency_get(void *data, u64 *val)
{
*val = tegra_emc_bw_efficiency;
return 0;
}
static int efficiency_set(void *data, u64 val)
{
tegra_emc_bw_efficiency = (val > 100) ? 100 : val;
if (emc)
tegra_clk_shared_bus_update(emc);
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(efficiency_fops, efficiency_get,
efficiency_set, "%llu\n");
static int __init tegra_emc_debug_init(void)
{
emc_debugfs_root = debugfs_create_dir("tegra_emc", NULL);
if (!emc_debugfs_root)
return -ENOMEM;
if (!debugfs_create_file(
"table_info", S_IRUGO, emc_debugfs_root, NULL,
&emc_table_info_fops))
goto err_out;
if (!tegra_emc_table)
return 0;
if (!debugfs_create_file(
"stats", S_IRUGO, emc_debugfs_root, NULL, &emc_stats_fops))
goto err_out;
if (!debugfs_create_u32("clkchange_delay", S_IRUGO | S_IWUSR,
emc_debugfs_root, (u32 *)&clkchange_delay))
goto err_out;
if (!debugfs_create_file("dram_temperature", S_IRUGO, emc_debugfs_root,
NULL, &dram_temperature_fops))
goto err_out;
if (!debugfs_create_file("efficiency", S_IRUGO | S_IWUSR,
emc_debugfs_root, NULL, &efficiency_fops))
goto err_out;
if (tegra_emc_iso_usage_debugfs_init(emc_debugfs_root))
goto err_out;
return 0;
err_out:
debugfs_remove_recursive(emc_debugfs_root);
return -ENOMEM;
}
late_initcall(tegra_emc_debug_init);
#endif