123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477 |
- /*******************************************************************
- *
- * File: ddr_oxsemi.c
- *
- * Description: Declarations for DDR routines and data objects
- *
- * Author: Julien Margetts
- *
- * Copyright: Oxford Semiconductor Ltd, 2009
- */
- #include <common.h>
- #include <asm/arch/clock.h>
- #include "ddr.h"
- typedef unsigned int UINT;
- // DDR TIMING PARAMETERS
- typedef struct {
- unsigned int holdoff_cmd_A;
- unsigned int holdoff_cmd_ARW;
- unsigned int holdoff_cmd_N;
- unsigned int holdoff_cmd_LM;
- unsigned int holdoff_cmd_R;
- unsigned int holdoff_cmd_W;
- unsigned int holdoff_cmd_PC;
- unsigned int holdoff_cmd_RF;
- unsigned int holdoff_bank_R;
- unsigned int holdoff_bank_W;
- unsigned int holdoff_dir_RW;
- unsigned int holdoff_dir_WR;
- unsigned int holdoff_FAW;
- unsigned int latency_CAS;
- unsigned int latency_WL;
- unsigned int recovery_WR;
- unsigned int width_update;
- unsigned int odt_offset;
- unsigned int odt_drive_all;
- unsigned int use_fixed_re;
- unsigned int delay_wr_to_re;
- unsigned int wr_slave_ratio;
- unsigned int rd_slave_ratio0;
- unsigned int rd_slave_ratio1;
- } T_DDR_TIMING_PARAMETERS;
- // DDR CONFIG PARAMETERS
- typedef struct {
- unsigned int ddr_mode;
- unsigned int width;
- unsigned int blocs;
- unsigned int banks8;
- unsigned int rams;
- unsigned int asize;
- unsigned int speed;
- unsigned int cmd_mode_wr_cl_bl;
- } T_DDR_CONFIG_PARAMETERS;
- //cmd_mode_wr_cl_bl
- //when SDR : cmd_mode_wr_cl_bl = 0x80200002 + (latency_CAS_RAM * 16) + (recovery_WR - 1) * 512; -- Sets write rec XX, CL=XX; BL=8
- //else cmd_mode_wr_cl_bl = 0x80200003 + (latency_CAS_RAM * 16) + (recovery_WR - 1) * 512; -- Sets write rec XX, CL=XX; BL=8
- // cmd_ bank_ dir_ lat_ rec_ width_ odt_ odt_ fix delay ratio
- // A F C update offset all re re_to_we w r0 r1
- // R L P R R W A A W W
- //Timing Parameters A W N M R W C F R W W R W S L R
- static const T_DDR_TIMING_PARAMETERS C_TP_DDR2_25E_CL5_1GB = { 4, 5, 0, 2, 4, 4,
- 5, 51, 23, 24, 9, 11, 18, 5, 4, 6, 3, 2, 0, 1, 2, 75, 56, 56 }; //elida device.
- static const T_DDR_TIMING_PARAMETERS C_TP_DDR2_25E_CL5_2GB = { 4, 5, 0, 2, 4, 4,
- 5, 79, 22, 24, 9, 11, 20, 5, 4, 6, 3, 2, 0, 1, 2, 75, 56, 56 };
- static const T_DDR_TIMING_PARAMETERS C_TP_DDR2_25_CL6_1GB = { 4, 5, 0, 2, 4, 4,
- 4, 51, 22, 26, 10, 12, 18, 6, 5, 6, 3, 2, 0, 1, 2, 75, 56, 56 }; // 400MHz, Speedgrade 25 timings (1Gb parts)
- // D B B R A S
- // D W L K A S P
- //Config Parameters R D C 8 M Z D CMD_MODE
- //static const T_DDR_CONFIG_PARAMETERS C_CP_DDR2_25E_CL5 = { 2,16, 1, 0, 1, 32,25,0x80200A53}; // 64 MByte
- static const T_DDR_CONFIG_PARAMETERS C_CP_DDR2_25E_CL5 = { 2, 16, 1, 1, 1, 64,
- 25, 0x80200A53 }; // 128 MByte
- static const T_DDR_CONFIG_PARAMETERS C_CP_DDR2_25_CL6 = { 2, 16, 1, 1, 1, 128,
- 25, 0x80200A63 }; // 256 MByte
- static void ddr_phy_poll_until_locked(void)
- {
- volatile UINT reg_tmp = 0;
- volatile UINT locked = 0;
- //Extra read to put in delay before starting to poll...
- reg_tmp = *(volatile UINT *) C_DDR_REG_PHY2; // read
- //POLL C_DDR_PHY2_REG register until clock and flock
- //!!! Ideally have a timeout on this.
- while (locked == 0) {
- reg_tmp = *(volatile UINT *) C_DDR_REG_PHY2; // read
- //locked when bits 30 and 31 are set
- if (reg_tmp & 0xC0000000) {
- locked = 1;
- }
- }
- }
- static void ddr_poll_until_not_busy(void)
- {
- volatile UINT reg_tmp = 0;
- volatile UINT busy = 1;
- //Extra read to put in delay before starting to poll...
- reg_tmp = *(volatile UINT *) C_DDR_STAT_REG; // read
- //POLL DDR_STAT register until no longer busy
- //!!! Ideally have a timeout on this.
- while (busy == 1) {
- reg_tmp = *(volatile UINT *) C_DDR_STAT_REG; // read
- //when bit 31 is clear - core is no longer busy
- if ((reg_tmp & 0x80000000) == 0x00000000) {
- busy = 0;
- }
- }
- }
- static void ddr_issue_command(int commmand)
- {
- *(volatile UINT *) C_DDR_CMD_REG = commmand;
- ddr_poll_until_not_busy();
- }
- static void ddr_timing_initialisation(
- const T_DDR_TIMING_PARAMETERS *ddr_timing_parameters)
- {
- volatile UINT reg_tmp = 0;
- /* update the DDR controller registers for timing parameters */
- reg_tmp = (ddr_timing_parameters->holdoff_cmd_A << 0);
- reg_tmp = reg_tmp + (ddr_timing_parameters->holdoff_cmd_ARW << 4);
- reg_tmp = reg_tmp + (ddr_timing_parameters->holdoff_cmd_N << 8);
- reg_tmp = reg_tmp + (ddr_timing_parameters->holdoff_cmd_LM << 12);
- reg_tmp = reg_tmp + (ddr_timing_parameters->holdoff_cmd_R << 16);
- reg_tmp = reg_tmp + (ddr_timing_parameters->holdoff_cmd_W << 20);
- reg_tmp = reg_tmp + (ddr_timing_parameters->holdoff_cmd_PC << 24);
- *(volatile UINT *) C_DDR_REG_TIMING0 = reg_tmp;
- reg_tmp = (ddr_timing_parameters->holdoff_cmd_RF << 0);
- reg_tmp = reg_tmp + (ddr_timing_parameters->holdoff_bank_R << 8);
- reg_tmp = reg_tmp + (ddr_timing_parameters->holdoff_bank_W << 16);
- reg_tmp = reg_tmp + (ddr_timing_parameters->holdoff_dir_RW << 24);
- reg_tmp = reg_tmp + (ddr_timing_parameters->holdoff_dir_WR << 28);
- *(volatile UINT *) C_DDR_REG_TIMING1 = reg_tmp;
- reg_tmp = (ddr_timing_parameters->latency_CAS << 0);
- reg_tmp = reg_tmp + (ddr_timing_parameters->latency_WL << 4);
- reg_tmp = reg_tmp + (ddr_timing_parameters->holdoff_FAW << 8);
- reg_tmp = reg_tmp + (ddr_timing_parameters->width_update << 16);
- reg_tmp = reg_tmp + (ddr_timing_parameters->odt_offset << 21);
- reg_tmp = reg_tmp + (ddr_timing_parameters->odt_drive_all << 24);
- *(volatile UINT *) C_DDR_REG_TIMING2 = reg_tmp;
- /* Program the timing parameters in the PHY too */
- reg_tmp = (ddr_timing_parameters->use_fixed_re << 16)
- | (ddr_timing_parameters->delay_wr_to_re << 8)
- | (ddr_timing_parameters->latency_WL << 4)
- | (ddr_timing_parameters->latency_CAS << 0);
- *(volatile UINT *) C_DDR_REG_PHY_TIMING = reg_tmp;
- reg_tmp = ddr_timing_parameters->wr_slave_ratio;
- *(volatile UINT *) C_DDR_REG_PHY_WR_RATIO = reg_tmp;
- reg_tmp = ddr_timing_parameters->rd_slave_ratio0;
- reg_tmp += ddr_timing_parameters->rd_slave_ratio1 << 8;
- *(volatile UINT *) C_DDR_REG_PHY_RD_RATIO = reg_tmp;
- }
- static void ddr_normal_initialisation(
- const T_DDR_CONFIG_PARAMETERS *ddr_config_parameters, int mhz)
- {
- int i;
- volatile UINT tmp = 0;
- volatile UINT reg_tmp = 0;
- volatile UINT emr_cmd = 0;
- UINT refresh;
- //Total size of memory in Mbits...
- tmp = ddr_config_parameters->rams * ddr_config_parameters->asize
- * ddr_config_parameters->width;
- //Deduce value to program into DDR_CFG register...
- switch (tmp) {
- case 16:
- reg_tmp = 0x00020000 * 1;
- break;
- case 32:
- reg_tmp = 0x00020000 * 2;
- break;
- case 64:
- reg_tmp = 0x00020000 * 3;
- break;
- case 128:
- reg_tmp = 0x00020000 * 4;
- break;
- case 256:
- reg_tmp = 0x00020000 * 5;
- break;
- case 512:
- reg_tmp = 0x00020000 * 6;
- break;
- case 1024:
- reg_tmp = 0x00020000 * 7;
- break;
- case 2048:
- reg_tmp = 0x00020000 * 8;
- break;
- default:
- reg_tmp = 0; //forces sims not to work if badly configured
- }
- //Memory width
- tmp = ddr_config_parameters->rams * ddr_config_parameters->width;
- switch (tmp) {
- case 8:
- reg_tmp = reg_tmp + 0x00400000;
- break;
- case 16:
- reg_tmp = reg_tmp + 0x00200000;
- break;
- case 32:
- reg_tmp = reg_tmp + 0x00000000;
- break;
- default:
- reg_tmp = 0; //forces sims not to work if badly configured
- }
- //Setup DDR Mode
- switch (ddr_config_parameters->ddr_mode) {
- case 0:
- reg_tmp = reg_tmp + 0x00000000;
- break; //SDR
- case 1:
- reg_tmp = reg_tmp + 0x40000000;
- break; //DDR
- case 2:
- reg_tmp = reg_tmp + 0x80000000;
- break; //DDR2
- default:
- reg_tmp = 0; //forces sims not to work if badly configured
- }
- //Setup Banks
- if (ddr_config_parameters->banks8 == 1) {
- reg_tmp = reg_tmp + 0x00800000;
- }
- //Program DDR_CFG register...
- *(volatile UINT *) C_DDR_CFG_REG = reg_tmp;
- //Configure PHY0 reg - se_mode is bit 1,
- //needs to be 1 for DDR (single_ended drive)
- switch (ddr_config_parameters->ddr_mode) {
- case 0:
- reg_tmp = 2 + (0 << 4);
- break; //SDR
- case 1:
- reg_tmp = 2 + (4 << 4);
- break; //DDR
- case 2:
- reg_tmp = 0 + (4 << 4);
- break; //DDR2
- default:
- reg_tmp = 0;
- }
- //Program DDR_PHY0 register...
- *(volatile UINT *) C_DDR_REG_PHY0 = reg_tmp;
- //Read DDR_PHY* registers to exercise paths for vcd
- reg_tmp = *(volatile UINT *) C_DDR_REG_PHY3;
- reg_tmp = *(volatile UINT *) C_DDR_REG_PHY2;
- reg_tmp = *(volatile UINT *) C_DDR_REG_PHY1;
- reg_tmp = *(volatile UINT *) C_DDR_REG_PHY0;
- //Start up sequences - Different dependant on DDR mode
- switch (ddr_config_parameters->ddr_mode) {
- case 2: //DDR2
- //Start-up sequence: follows procedure described in Micron datasheet.
- //start up DDR PHY DLL
- reg_tmp = 0x00022828; // dll on, start point and inc = h28
- *(volatile UINT *) C_DDR_REG_PHY2 = reg_tmp;
- reg_tmp = 0x00032828; // start on, dll on, start point and inc = h28
- *(volatile UINT *) C_DDR_REG_PHY2 = reg_tmp;
- ddr_phy_poll_until_locked();
- udelay(200); //200us
- //Startup SDRAM...
- //!!! Software: CK should be running for 200us before wake-up
- ddr_issue_command( C_CMD_WAKE_UP);
- ddr_issue_command( C_CMD_NOP);
- ddr_issue_command( C_CMD_PRECHARGE_ALL);
- ddr_issue_command( C_CMD_DDR2_EMR2);
- ddr_issue_command( C_CMD_DDR2_EMR3);
- emr_cmd = C_CMD_DDR2_EMR1 + C_CMD_ODT_75 + C_CMD_REDUCED_DRIVE
- + C_CMD_ENABLE_DLL;
- ddr_issue_command(emr_cmd);
- //Sets CL=3; BL=8 but also reset DLL to trigger a DLL initialisation...
- udelay(1); //1us
- ddr_issue_command(
- ddr_config_parameters->cmd_mode_wr_cl_bl
- + C_CMD_RESET_DLL);
- udelay(1); //1us
- //!!! Software: Wait 200 CK cycles before...
- //for(i=1; i<=2; i++) {
- ddr_issue_command(C_CMD_PRECHARGE_ALL);
- // !!! Software: Wait here at least 8 CK cycles
- //}
- //need a wait here to ensure PHY DLL lock before the refresh is issued
- udelay(1); //1us
- for (i = 1; i <= 2; i++) {
- ddr_issue_command( C_CMD_AUTO_REFRESH);
- //!!! Software: Wait here at least 8 CK cycles to satify tRFC
- udelay(1); //1us
- }
- //As before but without 'RESET_DLL' bit set...
- ddr_issue_command(ddr_config_parameters->cmd_mode_wr_cl_bl);
- udelay(1); //1us
- // OCD commands
- ddr_issue_command(emr_cmd + C_CMD_MODE_DDR2_OCD_DFLT);
- ddr_issue_command(emr_cmd + C_CMD_MODE_DDR2_OCD_EXIT);
- break;
- default:
- break; //Do nothing
- }
- //Enable auto-refresh
- // 8192 Refreshes required every 64ms, so maximum refresh period is 7.8125 us
- // We have a 400 MHz DDR clock (2.5ns period) so max period is 3125 cycles
- // Our core now does 8 refreshes in a go, so we multiply this period by 8
- refresh = (64000 * mhz) / 8192; // Refresh period in clocks
- reg_tmp = *(volatile UINT *) C_DDR_CFG_REG; // read
- #ifdef BURST_REFRESH_ENABLE
- reg_tmp |= C_CFG_REFRESH_ENABLE | (refresh * 8);
- reg_tmp |= C_CFG_BURST_REFRESH_ENABLE;
- #else
- reg_tmp |= C_CFG_REFRESH_ENABLE | (refresh * 1);
- reg_tmp &= ~C_CFG_BURST_REFRESH_ENABLE;
- #endif
- *(volatile UINT *) C_DDR_CFG_REG = reg_tmp;
- //Verify register contents
- reg_tmp = *(volatile UINT *) C_DDR_REG_PHY2; // read
- //printf("Warning XXXXXXXXXXXXXXXXXXXXXX - get bad read data from C_DDR_PHY2_REG, though it looks OK on bus XXXXXXXXXXXXXXXXXX");
- //TBD Check_data (read_data, dll_reg, "Error: bad C_DDR_PHY2_REG read", tb_pass);
- reg_tmp = *(volatile UINT *) C_DDR_CFG_REG; // read
- //TBD Check_data (read_data, cfg_reg, "Error: bad DDR_CFG read", tb_pass);
- //disable optimised wrapping
- if (ddr_config_parameters->ddr_mode == 2) {
- reg_tmp = 0xFFFF0000;
- *(volatile UINT *) C_DDR_REG_IGNORE = reg_tmp;
- }
- //enable midbuffer followon
- reg_tmp = *(volatile UINT *) C_DDR_ARB_REG; // read
- reg_tmp = 0xFFFF0000 | reg_tmp;
- *(volatile UINT *) C_DDR_ARB_REG = reg_tmp;
- // Enable write behind coherency checking for all clients
- reg_tmp = 0xFFFF0000;
- *(volatile UINT *) C_DDR_AHB4_REG = reg_tmp;
- //Wait for 200 clock cycles for SDRAM DLL to lock...
- udelay(1); //1us
- }
- // Function used to Setup DDR core
- void ddr_setup(int mhz)
- {
- static const T_DDR_TIMING_PARAMETERS *ddr_timing_parameters =
- &C_TP_DDR2_25_CL6_1GB;
- static const T_DDR_CONFIG_PARAMETERS *ddr_config_parameters =
- &C_CP_DDR2_25_CL6;
- //Bring core out of Reset
- *(volatile UINT *) C_DDR_BLKEN_REG = C_BLKEN_DDR_ON;
- //DDR TIMING INITIALISTION
- ddr_timing_initialisation(ddr_timing_parameters);
- //DDR NORMAL INITIALISATION
- ddr_normal_initialisation(ddr_config_parameters, mhz);
- // route all writes through one client
- *(volatile UINT *) C_DDR_TRANSACTION_ROUTING = (0
- << DDR_ROUTE_CPU0_INSTR_SHIFT)
- | (1 << DDR_ROUTE_CPU0_RDDATA_SHIFT)
- | (3 << DDR_ROUTE_CPU0_WRDATA_SHIFT)
- | (2 << DDR_ROUTE_CPU1_INSTR_SHIFT)
- | (3 << DDR_ROUTE_CPU1_RDDATA_SHIFT)
- | (3 << DDR_ROUTE_CPU1_WRDATA_SHIFT);
- //Bring all clients out of reset
- *(volatile UINT *) C_DDR_BLKEN_REG = C_BLKEN_DDR_ON + 0x0000FFFF;
- }
- void set_ddr_timing(unsigned int w, unsigned int i)
- {
- unsigned int reg;
- unsigned int wnow = 16;
- unsigned int inow = 32;
- /* reset all timing controls to known value (31) */
- writel(DDR_PHY_TIMING_W_RST | DDR_PHY_TIMING_I_RST, DDR_PHY_TIMING);
- writel(DDR_PHY_TIMING_W_RST | DDR_PHY_TIMING_I_RST | DDR_PHY_TIMING_CK,
- DDR_PHY_TIMING);
- writel(DDR_PHY_TIMING_W_RST | DDR_PHY_TIMING_I_RST, DDR_PHY_TIMING);
- /* step up or down read delay to the requested value */
- while (wnow != w) {
- if (wnow < w) {
- reg = DDR_PHY_TIMING_INC;
- wnow++;
- } else {
- reg = 0;
- wnow--;
- }
- writel(DDR_PHY_TIMING_W_CE | reg, DDR_PHY_TIMING);
- writel(DDR_PHY_TIMING_CK | DDR_PHY_TIMING_W_CE | reg,
- DDR_PHY_TIMING);
- writel(DDR_PHY_TIMING_W_CE | reg, DDR_PHY_TIMING);
- }
- /* now write delay */
- while (inow != i) {
- if (inow < i) {
- reg = DDR_PHY_TIMING_INC;
- inow++;
- } else {
- reg = 0;
- inow--;
- }
- writel(DDR_PHY_TIMING_I_CE | reg, DDR_PHY_TIMING);
- writel(DDR_PHY_TIMING_CK | DDR_PHY_TIMING_I_CE | reg,
- DDR_PHY_TIMING);
- writel(DDR_PHY_TIMING_I_CE | reg, DDR_PHY_TIMING);
- }
- }
- //Function used to Setup SDRAM in DDR/SDR mode
- void init_ddr(int mhz)
- {
- /* start clocks */
- enable_clock(SYS_CTRL_CLK_DDRPHY);
- enable_clock(SYS_CTRL_CLK_DDR);
- enable_clock(SYS_CTRL_CLK_DDRCK);
- /* bring phy and core out of reset */
- reset_block(SYS_CTRL_RST_DDR_PHY, 0);
- reset_block(SYS_CTRL_RST_DDR, 0);
- /* DDR runs at half the speed of the CPU */
- ddr_setup(mhz >> 1);
- return;
- }
|