diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/cpu/allwinner/a10/dramc.h | 176 | ||||
-rw-r--r-- | src/cpu/allwinner/a10/raminit.c | 468 |
2 files changed, 644 insertions, 0 deletions
diff --git a/src/cpu/allwinner/a10/dramc.h b/src/cpu/allwinner/a10/dramc.h new file mode 100644 index 0000000000..7d44d83f44 --- /dev/null +++ b/src/cpu/allwinner/a10/dramc.h @@ -0,0 +1,176 @@ +/* + * Allwinner A10 platform dram register definition. + * + * Based on sun4i Linux kernel sources mach-sunxi/pm/standby/dram*.c + * and earlier U-Boot Allwiner A10 SPL work + * + * Copyright (C) 2007-2012 Allwinner Technology Co., Ltd. + * Berg Xing <bergxing@allwinnertech.com> + * Tom Cubie <tangliang@allwinnertech.com> + * Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com> + * Subject to the GNU GPL v2, or (at your option) any later version. + */ + +#ifndef CPU_ALLWINNER_A10_DRAMC_H +#define CPU_ALLWINNER_A10_DRAMC_H + +#include <types.h> + +#define DRAM_CCR_COMMAND_RATE_1T (0x1 << 5) +#define DRAM_CCR_DQS_GATE (0x1 << 14) +#define DRAM_CCR_DQS_DRIFT_COMP (0x1 << 17) +#define DRAM_CCR_ITM_OFF (0x1 << 28) +#define DRAM_CCR_DATA_TRAINING (0x1 << 30) +#define DRAM_CCR_INIT (0x1 << 31) + +#define DRAM_MEMORY_TYPE_DDR1 1 +#define DRAM_MEMORY_TYPE_DDR2 2 +#define DRAM_MEMORY_TYPE_DDR3 3 +#define DRAM_MEMORY_TYPE_LPDDR2 4 +#define DRAM_MEMORY_TYPE_LPDDR 5 +#define DRAM_DCR_TYPE (0x1 << 0) +#define DRAM_DCR_TYPE_DDR2 0x0 +#define DRAM_DCR_TYPE_DDR3 0x1 +#define DRAM_DCR_IO_WIDTH(n) (((n) & 0x3) << 1) +#define DRAM_DCR_IO_WIDTH_MASK DRAM_DCR_IO_WIDTH(0x3) +#define DRAM_DCR_IO_WIDTH_8BIT 0x0 +#define DRAM_DCR_IO_WIDTH_16BIT 0x1 +#define DRAM_DCR_CHIP_DENSITY(n) (((n) & 0x7) << 3) +#define DRAM_DCR_CHIP_DENSITY_MASK DRAM_DCR_CHIP_DENSITY(0x7) +#define DRAM_DCR_CHIP_DENSITY_256M 0x0 +#define DRAM_DCR_CHIP_DENSITY_512M 0x1 +#define DRAM_DCR_CHIP_DENSITY_1024M 0x2 +#define DRAM_DCR_CHIP_DENSITY_2048M 0x3 +#define DRAM_DCR_CHIP_DENSITY_4096M 0x4 +#define DRAM_DCR_CHIP_DENSITY_8192M 0x5 +#define DRAM_DCR_BUS_WIDTH(n) (((n) & 0x7) << 6) +#define DRAM_DCR_BUS_WIDTH_MASK DRAM_DCR_BUS_WIDTH(0x7) +#define DRAM_DCR_BUS_WIDTH_32BIT 0x3 +#define DRAM_DCR_BUS_WIDTH_16BIT 0x1 +#define DRAM_DCR_BUS_WIDTH_8BIT 0x0 +#define DRAM_DCR_NR_DLLCR_32BIT 5 +#define DRAM_DCR_NR_DLLCR_16BIT 3 +#define DRAM_DCR_NR_DLLCR_8BIT 2 +#define DRAM_DCR_RANK_SEL(n) (((n) & 0x3) << 10) +#define DRAM_DCR_RANK_SEL_MASK DRAM_DCR_CMD_RANK(0x3) +#define DRAM_DCR_CMD_RANK_ALL (0x1 << 12) +#define DRAM_DCR_MODE(n) (((n) & 0x3) << 13) +#define DRAM_DCR_MODE_MASK DRAM_DCR_MODE(0x3) +#define DRAM_DCR_MODE_SEQ 0x0 +#define DRAM_DCR_MODE_INTERLEAVE 0x1 + +#define DRAM_CSR_FAILED (0x1 << 20) + +#define DRAM_MCR_MODE_NORM(n) (((n) & 0x3) << 0) +#define DRAM_MCR_MODE_NORM_MASK DRAM_MCR_MOD_NORM(0x3) +#define DRAM_MCR_MODE_DQ_OUT(n) (((n) & 0x3) << 2) +#define DRAM_MCR_MODE_DQ_OUT_MASK DRAM_MCR_MODE_DQ_OUT(0x3) +#define DRAM_MCR_MODE_ADDR_OUT(n) (((n) & 0x3) << 4) +#define DRAM_MCR_MODE_ADDR_OUT_MASK DRAM_MCR_MODE_ADDR_OUT(0x3) +#define DRAM_MCR_MODE_DQ_IN_OUT(n) (((n) & 0x3) << 6) +#define DRAM_MCR_MODE_DQ_IN_OUT_MASK DRAM_MCR_MODE_DQ_IN_OUT(0x3) +#define DRAM_MCR_MODE_DQ_TURNON_DELAY(n) (((n) & 0x7) << 8) +#define DRAM_MCR_MODE_DQ_TURNON_DELAY_MASK DRAM_MCR_MODE_DQ_TURNON_DELAY(0x7) +#define DRAM_MCR_MODE_ADDR_IN (0x1 << 11) +#define DRAM_MCR_RESET (0x1 << 12) +#define DRAM_MCR_MODE_EN(n) (((n) & 0x3) << 13) +#define DRAM_MCR_MODE_EN_MASK DRAM_MCR_MOD_EN(0x3) +#define DRAM_MCR_DCLK_OUT (0x1 << 16) + +#define DRAM_DLLCR_NRESET (0x1 << 30) +#define DRAM_DLLCR_DISABLE (0x1 << 31) + +#define DRAM_ZQCR0_IMP_DIV(n) (((n) & 0xff) << 20) +#define DRAM_ZQCR0_IMP_DIV_MASK DRAM_ZQCR0_IMP_DIV(0xff) + +#define DRAM_IOCR_ODT_EN(n) ((((n) & 0x3) << 30) | ((n) & 0x3) << 0) +#define DRAM_IOCR_ODT_EN_MASK DRAM_IOCR_ODT_EN(0x3) + +#define DRAM_MR_BURST_LENGTH(n) (((n) & 0x7) << 0) +#define DRAM_MR_BURST_LENGTH_MASK DRAM_MR_BURST_LENGTH(0x7) +#define DRAM_MR_CAS_LAT(n) (((n) & 0x7) << 4) +#define DRAM_MR_CAS_LAT_MASK DRAM_MR_CAS_LAT(0x7) +#define DRAM_MR_WRITE_RECOVERY(n) (((n) & 0x7) << 9) +#define DRAM_MR_WRITE_RECOVERY_MASK DRAM_MR_WRITE_RECOVERY(0x7) +#define DRAM_MR_POWER_DOWN (0x1 << 12) + +#define DRAM_CSEL_MAGIC 0x16237495 + +struct a1x_dramc { + u32 ccr; /* 0x00 controller configuration register */ + u32 dcr; /* 0x04 dram configuration register */ + u32 iocr; /* 0x08 i/o configuration register */ + u32 csr; /* 0x0c controller status register */ + u32 drr; /* 0x10 dram refresh register */ + u32 tpr0; /* 0x14 dram timing parameters register 0 */ + u32 tpr1; /* 0x18 dram timing parameters register 1 */ + u32 tpr2; /* 0x1c dram timing parameters register 2 */ + u32 gdllcr; /* 0x20 global dll control register */ + u8 res0[0x28]; + u32 rslr0; /* 0x4c rank system latency register */ + u32 rslr1; /* 0x50 rank system latency register */ + u8 res1[0x8]; + u32 rdgr0; /* 0x5c rank dqs gating register */ + u32 rdgr1; /* 0x60 rank dqs gating register */ + u8 res2[0x34]; + u32 odtcr; /* 0x98 odt configuration register */ + u32 dtr0; /* 0x9c data training register 0 */ + u32 dtr1; /* 0xa0 data training register 1 */ + u32 dtar; /* 0xa4 data training address register */ + u32 zqcr0; /* 0xa8 zq control register 0 */ + u32 zqcr1; /* 0xac zq control register 1 */ + u32 zqsr; /* 0xb0 zq status register */ + u32 idcr; /* 0xb4 initializaton delay configure reg */ + u8 res3[0x138]; + u32 mr; /* 0x1f0 mode register */ + u32 emr; /* 0x1f4 extended mode register */ + u32 emr2; /* 0x1f8 extended mode register */ + u32 emr3; /* 0x1fc extended mode register */ + u32 dllctr; /* 0x200 dll control register */ + u32 dllcr[5]; /* 0x204 dll control register 0(byte 0) */ + /* 0x208 dll control register 1(byte 1) */ + /* 0x20c dll control register 2(byte 2) */ + /* 0x210 dll control register 3(byte 3) */ + /* 0x214 dll control register 4(byte 4) */ + u32 dqtr0; /* 0x218 dq timing register */ + u32 dqtr1; /* 0x21c dq timing register */ + u32 dqtr2; /* 0x220 dq timing register */ + u32 dqtr3; /* 0x224 dq timing register */ + u32 dqstr; /* 0x228 dqs timing register */ + u32 dqsbtr; /* 0x22c dqsb timing register */ + u32 mcr; /* 0x230 mode configure register */ + u8 res[0x8]; + u32 ppwrsctl; /* 0x23c pad power save control */ + u32 apr; /* 0x240 arbiter period register */ + u32 pldtr; /* 0x244 priority level data threshold reg */ + u8 res5[0x8]; + u32 hpcr[32]; /* 0x250 host port configure register */ + u8 res6[0x10]; + u32 csel; /* 0x2e0 controller select register */ +}; + +struct dram_para { + u32 clock; + u32 type; + u32 rank_num; + u32 density; + u32 io_width; + u32 bus_width; + u32 cas; + u32 zq; + u32 odt_en; + u32 size; + u32 tpr0; + u32 tpr1; + u32 tpr2; + u32 tpr3; + u32 tpr4; + u32 tpr5; + u32 emr1; + u32 emr2; + u32 emr3; +}; + +unsigned long dramc_init(struct dram_para *para); + +#endif /* CPU_ALLWINNER_A10_DRAMC_H */ diff --git a/src/cpu/allwinner/a10/raminit.c b/src/cpu/allwinner/a10/raminit.c new file mode 100644 index 0000000000..84fe4e8d99 --- /dev/null +++ b/src/cpu/allwinner/a10/raminit.c @@ -0,0 +1,468 @@ +/* + * Allwinner A10 DRAM controller initialization + * + * Based on sun4i Linux kernel sources mach-sunxi/pm/standby/dram*.c + * and earlier U-Boot Allwiner A10 SPL work + * + * Copyright (C) 2012 Henrik Nordstrom <henrik@henriknordstrom.net> + * Copyright (C) 2013 Luke Kenneth Casson Leighton <lkcl@lkcl.net> + * Copyright (C) 2007-2012 Allwinner Technology Co., Ltd. + * Berg Xing <bergxing@allwinnertech.com> + * Tom Cubie <tangliang@allwinnertech.com> + * Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com> + * Subject to the GNU GPL v2, or (at your option) any later version. + */ + +#include "clock.h" +#include "dramc.h" +#include "memmap.h" +#include "timer.h" + +#include <arch/io.h> +#include <console/console.h> +#include <delay.h> + +static struct a1x_dramc *const dram = (void *)A1X_DRAMC_BASE; + +static void mctl_ddr3_reset(void) +{ + if (a1x_get_cpu_chip_revision() != A1X_CHIP_REV_A) { + setbits_le32(&dram->mcr, DRAM_MCR_RESET); + udelay(2); + clrbits_le32(&dram->mcr, DRAM_MCR_RESET); + } else { + clrbits_le32(&dram->mcr, DRAM_MCR_RESET); + udelay(2); + setbits_le32(&dram->mcr, DRAM_MCR_RESET); + } +} + +static void mctl_set_drive(void) +{ + clrsetbits_le32(&dram->mcr, DRAM_MCR_MODE_NORM(0x3), + DRAM_MCR_MODE_EN(0x3) | 0xffc); +} + +static void mctl_itm_disable(void) +{ + clrsetbits_le32(&dram->ccr, DRAM_CCR_INIT, DRAM_CCR_ITM_OFF); +} + +static void mctl_itm_enable(void) +{ + clrbits_le32(&dram->ccr, DRAM_CCR_ITM_OFF); +} + +static void mctl_enable_dll0(u32 phase) +{ + clrsetbits_le32(&dram->dllcr[0], 0x3f << 6, + ((phase >> 16) & 0x3f) << 6); + clrsetbits_le32(&dram->dllcr[0], DRAM_DLLCR_NRESET, DRAM_DLLCR_DISABLE); + udelay(2); + + clrbits_le32(&dram->dllcr[0], DRAM_DLLCR_NRESET | DRAM_DLLCR_DISABLE); + udelay(22); + + clrsetbits_le32(&dram->dllcr[0], DRAM_DLLCR_DISABLE, DRAM_DLLCR_NRESET); + udelay(22); +} + +/* + * Note: This differs from pm/standby in that it checks the bus width + */ +static void mctl_enable_dllx(u32 phase) +{ + u32 i, n, bus_width; + + bus_width = read32(&dram->dcr); + + if ((bus_width & DRAM_DCR_BUS_WIDTH_MASK) == + DRAM_DCR_BUS_WIDTH(DRAM_DCR_BUS_WIDTH_32BIT)) + n = DRAM_DCR_NR_DLLCR_32BIT; + else + n = DRAM_DCR_NR_DLLCR_16BIT; + + for (i = 1; i < n; i++) { + clrsetbits_le32(&dram->dllcr[i], 0x4 << 14, + (phase & 0xf) << 14); + clrsetbits_le32(&dram->dllcr[i], DRAM_DLLCR_NRESET, + DRAM_DLLCR_DISABLE); + phase >>= 4; + } + udelay(2); + + for (i = 1; i < n; i++) + clrbits_le32(&dram->dllcr[i], DRAM_DLLCR_NRESET | + DRAM_DLLCR_DISABLE); + udelay(22); + + for (i = 1; i < n; i++) + clrsetbits_le32(&dram->dllcr[i], DRAM_DLLCR_DISABLE, + DRAM_DLLCR_NRESET); + udelay(22); +} + +static u32 hpcr_value[32] = { + 0x0301, 0x0301, 0x0301, 0x0301, + 0x0301, 0x0301, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0x1031, 0x1031, 0x0735, 0x1035, + 0x1035, 0x0731, 0x1031, 0x0735, + 0x1035, 0x1031, 0x0731, 0x1035, + 0x1031, 0x0301, 0x0301, 0x0731 +}; + +static void mctl_configure_hostport(void) +{ + u32 i; + + for (i = 0; i < 32; i++) + write32(hpcr_value[i], &dram->hpcr[i]); +} + +static void mctl_setup_dram_clock(u32 clk) +{ + /* setup DRAM PLL */ + a1x_pll5_configure(clk / 24, 2, 2, 1); + + /* FIXME: This bit is not documented for A10, and altering it doesn't + * seem to change anything. + * + * #define CCM_PLL5_CTRL_VCO_GAIN (0x1 << 19) + * reg_val = read32(&ccm->pll5_cfg); + * reg_val &= ~CCM_PLL5_CTRL_VCO_GAIN; // PLL VCO Gain off + * write32(reg_val, &ccm->pll5_cfg); + */ + udelay(5500); + + a1x_pll5_enable_dram_clock_output(); + + /* reset GPS */ + /* FIXME: These bits are also undocumented, and seem to have no effect + * on A10. + * + * #define CCM_GPS_CTRL_RESET (0x1 << 0) + * #define CCM_GPS_CTRL_GATE (0x1 << 1) + * clrbits_le32(&ccm->gps_clk_cfg, CCM_GPS_CTRL_RESET | CCM_GPS_CTRL_GATE); + */ + a1x_periph_clock_enable(A1X_CLKEN_GPS); + udelay(1); + a1x_periph_clock_disable(A1X_CLKEN_GPS); + + /* setup MBUS clock */ + /* FIXME: The MBUS does not seem to be present or do anything on A10. It + * is documented in the A13 user manual, but changing settings on A10 + * has no effect. + * + * #define CCM_MBUS_CTRL_M(n) (((n) & 0xf) << 0) + * #define CCM_MBUS_CTRL_M_MASK CCM_MBUS_CTRL_M(0xf) + * #define CCM_MBUS_CTRL_M_X(n) ((n) - 1) + * #define CCM_MBUS_CTRL_N(n) (((n) & 0xf) << 16) + * #define CCM_MBUS_CTRL_N_MASK CCM_MBUS_CTRL_N(0xf) + * #define CCM_MBUS_CTRL_N_X(n) (((n) >> 3) ? 3 : (((n) >> 2) ? 2 : (((n) >> 1) ? 1 : 0))) + * #define CCM_MBUS_CTRL_CLK_SRC(n) (((n) & 0x3) << 24) + * #define CCM_MBUS_CTRL_CLK_SRC_MASK CCM_MBUS_CTRL_CLK_SRC(0x3) + * #define CCM_MBUS_CTRL_CLK_SRC_HOSC 0x0 + * #define CCM_MBUS_CTRL_CLK_SRC_PLL6 0x1 + * #define CCM_MBUS_CTRL_CLK_SRC_PLL5 0x2 + * #define CCM_MBUS_CTRL_GATE (0x1 << 31) + * reg_val = CCM_MBUS_CTRL_GATE | + * CCM_MBUS_CTRL_CLK_SRC(CCM_MBUS_CTRL_CLK_SRC_PLL5) | + * CCM_MBUS_CTRL_N(CCM_MBUS_CTRL_N_X(1)) | + * CCM_MBUS_CTRL_M(CCM_MBUS_CTRL_M_X(2)); + * write32(reg_val, &ccm->mbus_clk_cfg); + */ + /* + * open DRAMC AHB & DLL register clock + * close it first + */ + a1x_periph_clock_disable(A1X_CLKEN_SDRAM); + + udelay(22); + + /* then open it */ + a1x_periph_clock_enable(A1X_CLKEN_SDRAM); + udelay(22); +} + +static int dramc_scan_readpipe(void) +{ + u32 reg32; + + /* data training trigger */ + setbits_le32(&dram->ccr, DRAM_CCR_DATA_TRAINING); + + /* check whether data training process has completed */ + while (read32(&dram->ccr) & DRAM_CCR_DATA_TRAINING) ; + + /* check data training result */ + reg32 = read32(&dram->csr); + if (reg32 & DRAM_CSR_FAILED) + return -1; + + return 0; +} + +static int dramc_scan_dll_para(void) +{ + const u32 dqs_dly[7] = { 0x3, 0x2, 0x1, 0x0, 0xe, 0xd, 0xc }; + const u32 clk_dly[15] = { 0x07, 0x06, 0x05, 0x04, 0x03, + 0x02, 0x01, 0x00, 0x08, 0x10, + 0x18, 0x20, 0x28, 0x30, 0x38 + }; + u32 clk_dqs_count[15]; + u32 dqs_i, clk_i, cr_i; + u32 max_val, min_val; + u32 dqs_index, clk_index; + + /* Find DQS_DLY Pass Count for every CLK_DLY */ + for (clk_i = 0; clk_i < 15; clk_i++) { + clk_dqs_count[clk_i] = 0; + clrsetbits_le32(&dram->dllcr[0], 0x3f << 6, + (clk_dly[clk_i] & 0x3f) << 6); + for (dqs_i = 0; dqs_i < 7; dqs_i++) { + for (cr_i = 1; cr_i < 5; cr_i++) { + clrsetbits_le32(&dram->dllcr[cr_i], + 0x4f << 14, + (dqs_dly[clk_i] & 0x4f) << 14); + } + udelay(2); + if (dramc_scan_readpipe() == 0) + clk_dqs_count[clk_i]++; + } + } + /* Test DQS_DLY Pass Count for every CLK_DLY from up to down */ + for (dqs_i = 15; dqs_i > 0; dqs_i--) { + max_val = 15; + min_val = 15; + for (clk_i = 0; clk_i < 15; clk_i++) { + if (clk_dqs_count[clk_i] == dqs_i) { + max_val = clk_i; + if (min_val == 15) + min_val = clk_i; + } + } + if (max_val < 15) + break; + } + + /* Check if Find a CLK_DLY failed */ + if (!dqs_i) + goto fail; + + /* Find the middle index of CLK_DLY */ + clk_index = (max_val + min_val) >> 1; + if ((max_val == (15 - 1)) && (min_val > 0)) + /* if CLK_DLY[MCTL_CLK_DLY_COUNT] is very good, then the middle + * value can be more close to the max_val + */ + clk_index = (15 + clk_index) >> 1; + else if ((max_val < (15 - 1)) && (min_val == 0)) + /* if CLK_DLY[0] is very good, then the middle value can be more + * close to the min_val + */ + clk_index >>= 1; + if (clk_dqs_count[clk_index] < dqs_i) + clk_index = min_val; + + /* Find the middle index of DQS_DLY for the CLK_DLY got above, and Scan + * read pipe again + */ + clrsetbits_le32(&dram->dllcr[0], 0x3f << 6, + (clk_dly[clk_index] & 0x3f) << 6); + max_val = 7; + min_val = 7; + for (dqs_i = 0; dqs_i < 7; dqs_i++) { + clk_dqs_count[dqs_i] = 0; + for (cr_i = 1; cr_i < 5; cr_i++) { + clrsetbits_le32(&dram->dllcr[cr_i], + 0x4f << 14, + (dqs_dly[dqs_i] & 0x4f) << 14); + } + udelay(2); + if (dramc_scan_readpipe() == 0) { + clk_dqs_count[dqs_i] = 1; + max_val = dqs_i; + if (min_val == 7) + min_val = dqs_i; + } + } + + if (max_val < 7) { + dqs_index = (max_val + min_val) >> 1; + if ((max_val == (7 - 1)) && (min_val > 0)) + dqs_index = (7 + dqs_index) >> 1; + else if ((max_val < (7 - 1)) && (min_val == 0)) + dqs_index >>= 1; + if (!clk_dqs_count[dqs_index]) + dqs_index = min_val; + for (cr_i = 1; cr_i < 5; cr_i++) { + clrsetbits_le32(&dram->dllcr[cr_i], + 0x4f << 14, + (dqs_dly[dqs_index] & 0x4f) << 14); + } + udelay(2); + return dramc_scan_readpipe(); + } + + fail: + clrbits_le32(&dram->dllcr[0], 0x3f << 6); + for (cr_i = 1; cr_i < 5; cr_i++) + clrbits_le32(&dram->dllcr[cr_i], 0x4f << 14); + udelay(2); + + return dramc_scan_readpipe(); +} + +static void dramc_set_autorefresh_cycle(u32 clk) +{ + u32 reg32; + u32 tmp_val; + u32 reg_dcr; + + if (clk < 600) { + reg_dcr = read32(&dram->dcr); + if ((reg_dcr & DRAM_DCR_CHIP_DENSITY_MASK) <= + DRAM_DCR_CHIP_DENSITY(DRAM_DCR_CHIP_DENSITY_1024M)) + reg32 = (131 * clk) >> 10; + else + reg32 = (336 * clk) >> 10; + + tmp_val = (7987 * clk) >> 10; + tmp_val = tmp_val * 9 - 200; + reg32 |= tmp_val << 8; + reg32 |= 0x8 << 24; + write32(reg32, &dram->drr); + } else { + write32(0x0, &dram->drr); + } +} + +unsigned long dramc_init(struct dram_para *para) +{ + u32 reg32; + int ret_val; + + /* check input dram parameter structure */ + if (!para) + return 0; + + /* setup DRAM relative clock */ + mctl_setup_dram_clock(para->clock); + + /* reset external DRAM */ + mctl_ddr3_reset(); + + mctl_set_drive(); + + /* dram clock off */ + a1x_gate_dram_clock_output(); + + /* select dram controller 1 */ + write32(DRAM_CSEL_MAGIC, &dram->csel); + + mctl_itm_disable(); + mctl_enable_dll0(para->tpr3); + + /* configure external DRAM */ + reg32 = 0x0; + if (para->type == DRAM_MEMORY_TYPE_DDR3) + reg32 |= DRAM_DCR_TYPE_DDR3; + reg32 |= DRAM_DCR_IO_WIDTH(para->io_width >> 3); + + if (para->density == 256) + reg32 |= DRAM_DCR_CHIP_DENSITY(DRAM_DCR_CHIP_DENSITY_256M); + else if (para->density == 512) + reg32 |= DRAM_DCR_CHIP_DENSITY(DRAM_DCR_CHIP_DENSITY_512M); + else if (para->density == 1024) + reg32 |= DRAM_DCR_CHIP_DENSITY(DRAM_DCR_CHIP_DENSITY_1024M); + else if (para->density == 2048) + reg32 |= DRAM_DCR_CHIP_DENSITY(DRAM_DCR_CHIP_DENSITY_2048M); + else if (para->density == 4096) + reg32 |= DRAM_DCR_CHIP_DENSITY(DRAM_DCR_CHIP_DENSITY_4096M); + else if (para->density == 8192) + reg32 |= DRAM_DCR_CHIP_DENSITY(DRAM_DCR_CHIP_DENSITY_8192M); + else + reg32 |= DRAM_DCR_CHIP_DENSITY(DRAM_DCR_CHIP_DENSITY_256M); + + reg32 |= DRAM_DCR_BUS_WIDTH((para->bus_width >> 3) - 1); + reg32 |= DRAM_DCR_RANK_SEL(para->rank_num - 1); + reg32 |= DRAM_DCR_CMD_RANK_ALL; + reg32 |= DRAM_DCR_MODE(DRAM_DCR_MODE_INTERLEAVE); + write32(reg32, &dram->dcr); + + /* dram clock on */ + a1x_ungate_dram_clock_output(); + + udelay(1); + + while (read32(&dram->ccr) & DRAM_CCR_INIT) ; + + mctl_enable_dllx(para->tpr3); + + /* set odt impendance divide ratio */ + reg32 = ((para->zq) >> 8) & 0xfffff; + reg32 |= ((para->zq) & 0xff) << 20; + reg32 |= (para->zq) & 0xf0000000; + write32(reg32, &dram->zqcr0); + + /* set I/O configure register */ + reg32 = 0x00cc0000; + reg32 |= (para->odt_en) & 0x3; + reg32 |= ((para->odt_en) & 0x3) << 30; + write32(reg32, &dram->iocr); + + /* set refresh period */ + dramc_set_autorefresh_cycle(para->clock); + + /* set timing parameters */ + write32(para->tpr0, &dram->tpr0); + write32(para->tpr1, &dram->tpr1); + write32(para->tpr2, &dram->tpr2); + + if (para->type == DRAM_MEMORY_TYPE_DDR3) { + reg32 = DRAM_MR_BURST_LENGTH(0x0); + reg32 |= DRAM_MR_CAS_LAT(para->cas - 4); + reg32 |= DRAM_MR_WRITE_RECOVERY(0x5); + } else if (para->type == DRAM_MEMORY_TYPE_DDR2) { + reg32 = DRAM_MR_BURST_LENGTH(0x2); + reg32 |= DRAM_MR_CAS_LAT(para->cas); + reg32 |= DRAM_MR_WRITE_RECOVERY(0x5); + } + write32(reg32, &dram->mr); + + write32(para->emr1, &dram->emr); + write32(para->emr2, &dram->emr2); + write32(para->emr3, &dram->emr3); + + /* set DQS window mode */ + clrsetbits_le32(&dram->ccr, DRAM_CCR_DQS_DRIFT_COMP, DRAM_CCR_DQS_GATE); + + /* reset external DRAM */ + setbits_le32(&dram->ccr, DRAM_CCR_INIT); + while (read32(&dram->ccr) & DRAM_CCR_INIT) ; + + /* scan read pipe value */ + mctl_itm_enable(); + if (para->tpr3 & (0x1 << 31)) { + ret_val = dramc_scan_dll_para(); + if (ret_val == 0) + para->tpr3 = + (((read32(&dram->dllcr[0]) >> 6) & 0x3f) << 16) | + (((read32(&dram->dllcr[1]) >> 14) & 0xf) << 0) | + (((read32(&dram->dllcr[2]) >> 14) & 0xf) << 4) | + (((read32(&dram->dllcr[3]) >> 14) & 0xf) << 8) | + (((read32(&dram->dllcr[4]) >> 14) & 0xf) << 12); + } else { + ret_val = dramc_scan_readpipe(); + } + + if (ret_val < 0) + return 0; + + /* configure all host port */ + mctl_configure_hostport(); + + return para->size; +} |