diff options
author | John Crispin <blogic@openwrt.org> | 2014-11-26 09:00:17 +0000 |
---|---|---|
committer | John Crispin <blogic@openwrt.org> | 2014-11-26 09:00:17 +0000 |
commit | 10bfe12b380e4a498b9447ee2fa35ab53539789a (patch) | |
tree | bd18a477f47a11b35f143cd550833ddb4e15572b /package/boot/uboot-oxnas/files/board/ox820/ddr.c | |
parent | 7d4dfd7dd7ce1ac02d84ad7482e3f7d168d61ec9 (diff) | |
download | master-187ad058-10bfe12b380e4a498b9447ee2fa35ab53539789a.tar.gz master-187ad058-10bfe12b380e4a498b9447ee2fa35ab53539789a.tar.bz2 master-187ad058-10bfe12b380e4a498b9447ee2fa35ab53539789a.zip |
add uboot-oxnas
This adds support for the oxnas target in U-Boot 2014.04
History can be found at https://github.com/kref/u-boot-oxnas up to 2013.10
changes from 2013.10 to 2014.04 can be followed at
https://gitorious.org/openwrt-oxnas
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@43389 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'package/boot/uboot-oxnas/files/board/ox820/ddr.c')
-rwxr-xr-x | package/boot/uboot-oxnas/files/board/ox820/ddr.c | 477 |
1 files changed, 477 insertions, 0 deletions
diff --git a/package/boot/uboot-oxnas/files/board/ox820/ddr.c b/package/boot/uboot-oxnas/files/board/ox820/ddr.c new file mode 100755 index 0000000000..a665722e3b --- /dev/null +++ b/package/boot/uboot-oxnas/files/board/ox820/ddr.c @@ -0,0 +1,477 @@ +/******************************************************************* + * + * 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; +} |