/*********************************************************************** * * Function: sdr_sdram_setup * * Purpose: Setup SDRAM * * Processing: * See function. * * Parameters: * clk : Base SDRAM controller clock rate * lp : Low power SDRAM flag * * Outputs: None * * Returns: Nothing * * Notes: None * **********************************************************************/ void sdr_sdram_setup(UNS_32 clk, int lp) { volatile UNS_32 tmp32; UNS_32 tmp; /* Enables SDR clocking mode, (7*0.25nS) HCLK delay Tests of HCLK delay have shown that voltage and frequency are not driving factors for it's timing. Over testing, a working value of 3 to 27 (average) appears to work and not effect other operation. For this value, a hardcoded value of 7 is used. */ CLKPWR->clkpwr_sdramclk_ctrl = CLKPWR_SDRCLK_HCLK_DLY(7); /* Setup slew rates */ #ifdef SDRAM_USE_SLOW_SLEW CLKPWR->clkpwr_sdramclk_ctrl |= (CLKPWR_SDRCLK_SLOWSLEW_CLK | CLKPWR_SDRCLK_SLOWSLEW | CLKPWR_SDRCLK_SLOWSLEW_DAT); #else CLKPWR->clkpwr_sdramclk_ctrl &= ~(CLKPWR_SDRCLK_SLOWSLEW_CLK | CLKPWR_SDRCLK_SLOWSLEW | CLKPWR_SDRCLK_SLOWSLEW_DAT); #endif tmp = sdram_find_config(); if (!tmp) { /* Nothing matches, exit, DRAM won't work */ return; } /* Setup address mapping, its ok to use low power SDRAM mode with standard SDRAM devices */ EMC->emcdynamicconfig0 = (tmp << 7) | EMC_DYN_DEV_LP_SDR_SDRAM; /* Setup CAS and RAS latencies */ EMC->emcdynamicrascas0 = EMC_SET_CAS_IN_HALF_CYCLES(SDRAM_CAS_LATENCY) | EMC_SET_RAS_IN_CYCLES(SDRAM_RAS_LATENCY); #ifdef USE_DUAL_SDRAM_DEVICES /* DYCS1 chip select */ EMC->emcdynamicconfig1 = (tmp << 7) | EMC_DYN_DEV_LP_SDR_SDRAM; EMC->emcdynamicrascas1 = EMC_SET_CAS_IN_HALF_CYCLES(SDRAM_CAS_LATENCY) | EMC_SET_RAS_IN_CYCLES(SDRAM_RAS_LATENCY); #endif /* Setup SDRAM read strategy */ EMC->emcdynamicreadconfig = (EMC_SDR_CLK_NODLY_CMD_DEL | EMC_SDR_READCAP_POS_POL); /* Setup SDRAM timing for current HCLK clock settings */ sdram_adjust_timing(clk); /* Enable clocks and delay for at least 100uS to stabilize */ tmp = (EMC_DYN_CLK_ALWAYS_ON | EMC_DYN_CLKEN_ALWAYS_ON | EMC_DYN_DIS_INV_MEMCLK); EMC->emcdynamiccontrol = (tmp | EMC_DYN_NOP_MODE); timer_wait_us(TIMER_CNTR0, 100); /* Issue a precharge all command */ EMC->emcdynamiccontrol = (tmp | EMC_DYN_PALL_MODE); EMC->emcdynamicrefresh = EMC_DYN_REFRESH_IVAL(4); timer_wait_us(TIMER_CNTR0, 10); /* Fast dynamic refresh for at least a few SDRAM clock cycles */ timer_wait_us(TIMER_CNTR0, 10); /* Normal refresh timing */ EMC->emcdynamicrefresh = EMC_DYN_REFRESH_IVAL(clk / SDRAM_RFSH_INTERVAL); /* Issue load mode command and normal mode word */ EMC->emcdynamiccontrol = (tmp | EMC_DYN_CMD_MODE); tmp32 = * (volatile UNS_32 *) (EMC_DYCS0_BASE + (SDRAM_MODE_WORD << modeshift)); #ifdef ENABLE_DEBUG modeaddr = EMC_DYCS0_BASE + (SDRAM_MODE_WORD << modeshift); #endif timer_wait_us(TIMER_CNTR0, 1); /* Only mobile (low power) SDRAMs use the extended mode word */ if (lp) { tmp32 = * (volatile UNS_32 *) (EMC_DYCS0_BASE + SDRAM_EXT_MODE_BB + (SDRAM_EXT_MODE_WORD << modeshift)); #ifdef ENABLE_DEBUG extmodeaddr = EMC_DYCS0_BASE + SDRAM_EXT_MODE_BB + (SDRAM_EXT_MODE_WORD << modeshift); #endif timer_wait_us(TIMER_CNTR0, 1); } #ifdef USE_DUAL_SDRAM_DEVICES /* Configuration for other chip select */ tmp32 = * (volatile UNS_32 *) (EMC_DYCS1_BASE + (SDRAM_MODE_WORD << modeshift)); timer_wait_us(TIMER_CNTR0, 1); if (lp) { tmp32 = * (volatile UNS_32 *) (EMC_DYCS1_BASE + SDRAM_EXT_MODE_BB + (SDRAM_EXT_MODE_WORD << modeshift)); timer_wait_us(TIMER_CNTR0, 1); } #endif /* Normal SDRAM mode */ EMC->emcdynamiccontrol = EMC_DYN_NORMAL_MODE | EMC_DYN_DIS_INV_MEMCLK | EMC_DYN_DIS_MEMCLK_IN_SFRSH; timer_wait_us(TIMER_CNTR0, 1); }
/*********************************************************************** * * Function: ddr_if_init * * Purpose: Sets up DDR interface and initial calibration * * Processing: * See function. * * Parameters: * cfg: Dynamic configuration value * * Outputs: None * * Returns: Nothing * * Notes: None * **********************************************************************/ static void ddr_if_init(UNS_32 cfg) { UNS_32 tmp, ringosccount; int idx; /* Use nominal rate for DDR clocking */ tmp = CLKPWR->clkpwr_hclk_div & ~(0x3 << 0x7); CLKPWR->clkpwr_hclk_div = tmp | CLKPWR_HCLKDIV_DDRCLK_NORM; /* Resync DDR clocks */ ddr_clock_resync(cfg); /* Enable calibration logic with low calibration sensitivity and a guessed first DQSIN delay value. This is just temporary and is used for the next step. */ CLKPWR->clkpwr_sdramclk_ctrl |= CLKPWR_SDRCLK_USE_CAL | CLKPWR_SDRCLK_SENS_FACT(7) | CLKPWR_SDRCLK_DQS_DLY(0xF); /* Force calibration 10 times and save the average value */ ringosccount = 0; for (idx = 0; idx < 10; idx++) { CLKPWR->clkpwr_sdramclk_ctrl |= CLKPWR_SDRCLK_DO_CAL; CLKPWR->clkpwr_sdramclk_ctrl &= ~CLKPWR_SDRCLK_DO_CAL; timer_wait_ms(TIMER_CNTR0, 25); ringosccount += CLKPWR->clkpwr_ddr_lap_count; } /* use the average for the nominal ring oscillator value */ CLKPWR->clkpwr_ddr_lap_nom = ringosccount / 10; /* Enable automatic RTC tick calibration, but keep calibration off for now until uncalibrated DQS delay is found. */ CLKPWR->clkpwr_sdramclk_ctrl |= CLKPWR_SDRCLK_CAL_ON_RTC; CLKPWR->clkpwr_sdramclk_ctrl &= ~CLKPWR_SDRCLK_USE_CAL; /* Setup CAS and RAS latencies */ EMC->emcdynamicrascas0 = EMC_SET_CAS_IN_HALF_CYCLES(SDRAM_CAS_LATENCY) | EMC_SET_RAS_IN_CYCLES(SDRAM_RAS_LATENCY); #ifdef USE_DUAL_SDRAM_DEVICES EMC->emcdynamicrascas1 = EMC_SET_CAS_IN_HALF_CYCLES(SDRAM_CAS_LATENCY) | EMC_SET_RAS_IN_CYCLES(SDRAM_RAS_LATENCY); #endif /* Setup DDR read strategy */ EMC->emcdynamicreadconfig = (EMC_SDR_CLK_NODLY_CMD_DEL | EMC_SDR_READCAP_POS_POL | EMC_DDR_CLK_NODLY_CMD_DEL); /* Setup slew rates */ #ifdef SDRAM_USE_SLOW_SLEW CLKPWR->clkpwr_sdramclk_ctrl |= (CLKPWR_SDRCLK_SLOWSLEW_CLK | CLKPWR_SDRCLK_SLOWSLEW | CLKPWR_SDRCLK_SLOWSLEW_DAT); #else CLKPWR->clkpwr_sdramclk_ctrl &= ~(CLKPWR_SDRCLK_SLOWSLEW_CLK | CLKPWR_SDRCLK_SLOWSLEW | CLKPWR_SDRCLK_SLOWSLEW_DAT); #endif }