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 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], emc0_base + emc_trimmer_offs[i]); __raw_writel(next_timing->emc_trimmers_1[i], emc1_base + emc_trimmer_offs[i]); } if ((dram_type == DRAM_TYPE_LPDDR2) && (dram_over_temp_state != DRAM_OVER_TEMP_NONE)) set_over_temp_timing(next_timing, dram_over_temp_state); 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 }