diff options
author | Alex Frid <afrid@nvidia.com> | 2012-09-13 15:53:21 -0700 |
---|---|---|
committer | Simone Willett <swillett@nvidia.com> | 2012-10-10 16:22:29 -0700 |
commit | 17d1ff4a633819ae9ea40682e6f463c3c48656a1 (patch) | |
tree | 0e51f9fb9ed11b80d682fcc56d02c90f90051ec6 /arch/arm/mach-tegra/tegra11_emc.c | |
parent | dee4cbe12d4bb9b6d402f215fd421a41cafdd2ac (diff) |
ARM: tegra11: clock: Update EMC clock change procedure
Added new fields to EMC timing table:
- registers that are updated before/after clock change if EMC
rate is decreased/increased, respectively
- trimmers that are set differently for EMC channel 0 and 1
- numbers of registers specified for each rate node
Updated nomenclature of individually controlled registers.
Updated clock change procedure accordingly.
Reviewed-on: http://git-master/r/132821
(cherry picked from commit 33c9a8f102baae511308c236277cd1cf90a78549)
Change-Id: I1b8ad8a8b22edfce59590245bb98938f62937797
Signed-off-by: Alex Frid <afrid@nvidia.com>
Signed-off-by: Deepak Nibade <dnibade@nvidia.com>
Reviewed-on: http://git-master/r/143041
Reviewed-by: Simone Willett <swillett@nvidia.com>
Tested-by: Simone Willett <swillett@nvidia.com>
Diffstat (limited to 'arch/arm/mach-tegra/tegra11_emc.c')
-rw-r--r-- | arch/arm/mach-tegra/tegra11_emc.c | 197 |
1 files changed, 185 insertions, 12 deletions
diff --git a/arch/arm/mach-tegra/tegra11_emc.c b/arch/arm/mach-tegra/tegra11_emc.c index a71c4b74da85..1f3f4946b483 100644 --- a/arch/arm/mach-tegra/tegra11_emc.c +++ b/arch/arm/mach-tegra/tegra11_emc.c @@ -69,36 +69,179 @@ enum { #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_QSAFE), \ + 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_DQS1), \ + DEFINE_REG(TEGRA_EMC_BASE, EMC_DLL_XFORM_DQS2), \ + DEFINE_REG(TEGRA_EMC_BASE, EMC_DLL_XFORM_DQS3), \ + 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_QUSE1), \ + DEFINE_REG(TEGRA_EMC_BASE, EMC_DLL_XFORM_QUSE2), \ + DEFINE_REG(TEGRA_EMC_BASE, EMC_DLL_XFORM_QUSE3), \ + 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_DLL_XFORM_ADDR1), \ + DEFINE_REG(TEGRA_EMC_BASE, EMC_DLL_XFORM_ADDR2), \ + DEFINE_REG(TEGRA_EMC_BASE, EMC_DLI_TRIM_TXDQS1), \ + DEFINE_REG(TEGRA_EMC_BASE, EMC_DLI_TRIM_TXDQS2), \ + DEFINE_REG(TEGRA_EMC_BASE, EMC_DLI_TRIM_TXDQS3), \ + 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_DLL_XFORM_DQ1), \ + DEFINE_REG(TEGRA_EMC_BASE, EMC_DLL_XFORM_DQ2), \ + DEFINE_REG(TEGRA_EMC_BASE, EMC_DLL_XFORM_DQ3), \ 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_XM2DQSPADCTRL3), \ + 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_MC_BASE, MC_EMEM_ARB_MISC0), + 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 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_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_CDB_CNTL_1), + #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 -static int emc_num_burst_regs; - struct emc_sel { struct clk *input; u32 value; @@ -130,6 +273,8 @@ static struct { 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); @@ -217,6 +362,7 @@ static inline void auto_cal_disable(void) static inline bool dqs_preset(const struct tegra11_emc_table *next_timing, const struct tegra11_emc_table *last_timing) { +#ifdef TEGRA_EMC_DQS_PRESET bool ret = false; #define DQS_SET(reg, bit) \ @@ -235,6 +381,9 @@ static inline bool dqs_preset(const struct tegra11_emc_table *next_timing, DQS_SET(XM2DQSPADCTRL3, VREF); return ret; +#else + return true; +#endif } static inline void overwrite_mrs_wait_cnt( @@ -332,7 +481,7 @@ static noinline void emc_set_clock(const struct tegra11_emc_table *next_timing, const struct tegra11_emc_table *last_timing, u32 clk_setting) { -#if 1 +#ifndef EMULATE_CLOCK_SWITCH int i, dll_change, pre_wait; bool dyn_sref_enabled, vref_cal_toggle, zcal_long; @@ -377,11 +526,17 @@ static noinline void emc_set_clock(const struct tegra11_emc_table *next_timing, auto_cal_disable(); /* 4. program burst shadow registers */ - for (i = 0; i < emc_num_burst_regs; i++) { + 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]); + } wmb(); barrier(); @@ -418,6 +573,14 @@ static noinline void emc_set_clock(const struct tegra11_emc_table *next_timing, ccfifo_writel(EMC_ZQ_CAL_LONG_CMD_DEV1, EMC_ZQ_CAL); } + /* 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); @@ -425,13 +588,21 @@ static noinline void emc_set_clock(const struct tegra11_emc_table *next_timing, /* 14.1 re-enable auto-refresh */ emc_writel(EMC_REFCTRL_ENABLE_ALL(dram_dev_num), EMC_REFCTRL); + /* 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. restore auto-cal */ if (vref_cal_toggle) emc_writel(next_timing->emc_acal_interval, EMC_AUTO_CAL_INTERVAL); /* 16. restore dynamic self-refresh */ - if (next_timing->emc_dsr) { + 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); } @@ -454,7 +625,9 @@ static inline void emc_get_timing(struct tegra11_emc_table *timing) { int i; - for (i = 0; i < emc_num_burst_regs; i++) { + /* burst array update depends on previous state; burst_up_down + and trimmers 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 @@ -466,8 +639,7 @@ static inline void emc_get_timing(struct tegra11_emc_table *timing) timing->emc_mode_1 = 0; timing->emc_mode_2 = 0; timing->emc_mode_4 = 0; - timing->emc_periodic_qrst = (emc_readl(EMC_CFG) & - EMC_CFG_PERIODIC_QRST) ? 1 : 0; + timing->emc_cfg = emc_readl(EMC_CFG); timing->rate = clk_get_rate_locked(emc); } @@ -650,6 +822,7 @@ bool tegra_emc_is_parent_ready(unsigned long rate, struct clk **parent, return false; } +/* FIXME: take advantage of table->src_sel_reg */ static int find_matching_input(const struct tegra11_emc_table *table, struct clk *pll_c, struct emc_sel *emc_clk_sel) { @@ -779,7 +952,7 @@ static int init_emc_table(const struct tegra11_emc_table *table, int table_size) tegra_emc_table_size = min(table_size, TEGRA_EMC_TABLE_MAX_SIZE); switch (table[0].rev) { case 0x40: - emc_num_burst_regs = 105; /* FIXME: actual number */ + start_timing.burst_regs_num = table[0].burst_regs_num; break; default: pr_err("tegra: invalid EMC DFS table: unknown rev 0x%x\n", |