diff options
author | Thomas Abraham <thomas.ab@samsung.com> | 2015-08-03 17:58:00 +0530 |
---|---|---|
committer | Minkyu Kang <mk7.kang@samsung.com> | 2015-08-17 13:06:52 +0900 |
commit | 77b55e8cfcee9ce1a973bf4dad3e160dd0be01f3 (patch) | |
tree | 0ec9071faf7ea93eca773777c989f1da65aada24 /arch/arm/mach-exynos/dmc_common.c | |
parent | 632093b566569329bc6e5b0893bdca01de905314 (diff) | |
download | u-boot-imx-77b55e8cfcee9ce1a973bf4dad3e160dd0be01f3.zip u-boot-imx-77b55e8cfcee9ce1a973bf4dad3e160dd0be01f3.tar.gz u-boot-imx-77b55e8cfcee9ce1a973bf4dad3e160dd0be01f3.tar.bz2 |
ARM: exynos: move SoC sources to mach-exynos
Move arch/arm/cpu/armv7/exynos/* to arch/arm/mach-exynos/* to allow
reuse of existing code for ARMv8 based Exynos platforms.
Cc: Minkyu Kang <mk7.kang@samsung.com>
Cc: Albert Aribaud <albert.u.boot@aribaud.net>
Cc: Masahiro Yamada <yamada.m@jp.panasonic.com>
Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
Reviewed-by: Masahiro Yamada <yamada.masahiro@socionext.com>
Tested-by: Przemyslaw Marczak <p.marczak@samsung.com>
Acked-by: Przemyslaw Marczak <p.marczak@samsung.com>
Signed-off-by: Minkyu Kang <mk7.kang@samsung.com>
Diffstat (limited to 'arch/arm/mach-exynos/dmc_common.c')
-rw-r--r-- | arch/arm/mach-exynos/dmc_common.c | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/arch/arm/mach-exynos/dmc_common.c b/arch/arm/mach-exynos/dmc_common.c new file mode 100644 index 0000000..9b6ee69 --- /dev/null +++ b/arch/arm/mach-exynos/dmc_common.c @@ -0,0 +1,176 @@ +/* + * Mem setup common file for different types of DDR present on Exynos boards. + * + * Copyright (C) 2012 Samsung Electronics + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/arch/spl.h> + +#include "clock_init.h" +#include "common_setup.h" +#include "exynos5_setup.h" + +#define ZQ_INIT_TIMEOUT 10000 + +int dmc_config_zq(struct mem_timings *mem, uint32_t *phy0_con16, + uint32_t *phy1_con16, uint32_t *phy0_con17, + uint32_t *phy1_con17) +{ + unsigned long val = 0; + int i; + + /* + * ZQ Calibration: + * Select Driver Strength, + * long calibration for manual calibration + */ + val = PHY_CON16_RESET_VAL; + val |= mem->zq_mode_dds << PHY_CON16_ZQ_MODE_DDS_SHIFT; + val |= mem->zq_mode_term << PHY_CON16_ZQ_MODE_TERM_SHIFT; + val |= ZQ_CLK_DIV_EN; + writel(val, phy0_con16); + writel(val, phy1_con16); + + /* Disable termination */ + if (mem->zq_mode_noterm) + val |= PHY_CON16_ZQ_MODE_NOTERM_MASK; + writel(val, phy0_con16); + writel(val, phy1_con16); + + /* ZQ_MANUAL_START: Enable */ + val |= ZQ_MANUAL_STR; + writel(val, phy0_con16); + writel(val, phy1_con16); + + /* ZQ_MANUAL_START: Disable */ + val &= ~ZQ_MANUAL_STR; + + /* + * Since we are manaully calibrating the ZQ values, + * we are looping for the ZQ_init to complete. + */ + i = ZQ_INIT_TIMEOUT; + while ((readl(phy0_con17) & ZQ_DONE) != ZQ_DONE && i > 0) { + sdelay(100); + i--; + } + if (!i) + return -1; + writel(val, phy0_con16); + + i = ZQ_INIT_TIMEOUT; + while ((readl(phy1_con17) & ZQ_DONE) != ZQ_DONE && i > 0) { + sdelay(100); + i--; + } + if (!i) + return -1; + writel(val, phy1_con16); + + return 0; +} + +void update_reset_dll(uint32_t *phycontrol0, enum ddr_mode mode) +{ + unsigned long val; + + if (mode == DDR_MODE_DDR3) { + val = MEM_TERM_EN | PHY_TERM_EN | DMC_CTRL_SHGATE; + writel(val, phycontrol0); + } + + /* Update DLL Information: Force DLL Resyncronization */ + val = readl(phycontrol0); + val |= FP_RSYNC; + writel(val, phycontrol0); + + /* Reset Force DLL Resyncronization */ + val = readl(phycontrol0); + val &= ~FP_RSYNC; + writel(val, phycontrol0); +} + +void dmc_config_mrs(struct mem_timings *mem, uint32_t *directcmd) +{ + int channel, chip; + + for (channel = 0; channel < mem->dmc_channels; channel++) { + unsigned long mask; + + mask = channel << DIRECT_CMD_CHANNEL_SHIFT; + for (chip = 0; chip < mem->chips_to_configure; chip++) { + int i; + + mask |= chip << DIRECT_CMD_CHIP_SHIFT; + + /* Sending NOP command */ + writel(DIRECT_CMD_NOP | mask, directcmd); + + /* + * TODO(alim.akhtar@samsung.com): Do we need these + * delays? This one and the next were not there for + * DDR3. + */ + sdelay(0x10000); + + /* Sending EMRS/MRS commands */ + for (i = 0; i < MEM_TIMINGS_MSR_COUNT; i++) { + writel(mem->direct_cmd_msr[i] | mask, + directcmd); + sdelay(0x10000); + } + + if (mem->send_zq_init) { + /* Sending ZQINIT command */ + writel(DIRECT_CMD_ZQINIT | mask, + directcmd); + + sdelay(10000); + } + } + } +} + +void dmc_config_prech(struct mem_timings *mem, uint32_t *directcmd) +{ + int channel, chip; + + for (channel = 0; channel < mem->dmc_channels; channel++) { + unsigned long mask; + + mask = channel << DIRECT_CMD_CHANNEL_SHIFT; + for (chip = 0; chip < mem->chips_per_channel; chip++) { + mask |= chip << DIRECT_CMD_CHIP_SHIFT; + + /* PALL (all banks precharge) CMD */ + writel(DIRECT_CMD_PALL | mask, directcmd); + sdelay(0x10000); + } + } +} + +void mem_ctrl_init(int reset) +{ + struct spl_machine_param *param = spl_get_machine_params(); + struct mem_timings *mem; + int ret; + + mem = clock_get_mem_timings(); + + /* If there are any other memory variant, add their init call below */ + if (param->mem_type == DDR_MODE_DDR3) { + ret = ddr3_mem_ctrl_init(mem, reset); + if (ret) { + /* will hang if failed to init memory control */ + while (1) + ; + } + } else { + /* will hang if unknow memory type */ + while (1) + ; + } +} |