1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
277b55e8cSThomas Abraham /*
377b55e8cSThomas Abraham * Mem setup common file for different types of DDR present on Exynos boards.
477b55e8cSThomas Abraham *
577b55e8cSThomas Abraham * Copyright (C) 2012 Samsung Electronics
677b55e8cSThomas Abraham */
777b55e8cSThomas Abraham
877b55e8cSThomas Abraham #include <common.h>
977b55e8cSThomas Abraham #include <asm/arch/spl.h>
1077b55e8cSThomas Abraham
1177b55e8cSThomas Abraham #include "clock_init.h"
1277b55e8cSThomas Abraham #include "common_setup.h"
1377b55e8cSThomas Abraham #include "exynos5_setup.h"
1477b55e8cSThomas Abraham
1577b55e8cSThomas Abraham #define ZQ_INIT_TIMEOUT 10000
1677b55e8cSThomas Abraham
dmc_config_zq(struct mem_timings * mem,uint32_t * phy0_con16,uint32_t * phy1_con16,uint32_t * phy0_con17,uint32_t * phy1_con17)1777b55e8cSThomas Abraham int dmc_config_zq(struct mem_timings *mem, uint32_t *phy0_con16,
1877b55e8cSThomas Abraham uint32_t *phy1_con16, uint32_t *phy0_con17,
1977b55e8cSThomas Abraham uint32_t *phy1_con17)
2077b55e8cSThomas Abraham {
2177b55e8cSThomas Abraham unsigned long val = 0;
2277b55e8cSThomas Abraham int i;
2377b55e8cSThomas Abraham
2477b55e8cSThomas Abraham /*
2577b55e8cSThomas Abraham * ZQ Calibration:
2677b55e8cSThomas Abraham * Select Driver Strength,
2777b55e8cSThomas Abraham * long calibration for manual calibration
2877b55e8cSThomas Abraham */
2977b55e8cSThomas Abraham val = PHY_CON16_RESET_VAL;
3077b55e8cSThomas Abraham val |= mem->zq_mode_dds << PHY_CON16_ZQ_MODE_DDS_SHIFT;
3177b55e8cSThomas Abraham val |= mem->zq_mode_term << PHY_CON16_ZQ_MODE_TERM_SHIFT;
3277b55e8cSThomas Abraham val |= ZQ_CLK_DIV_EN;
3377b55e8cSThomas Abraham writel(val, phy0_con16);
3477b55e8cSThomas Abraham writel(val, phy1_con16);
3577b55e8cSThomas Abraham
3677b55e8cSThomas Abraham /* Disable termination */
3777b55e8cSThomas Abraham if (mem->zq_mode_noterm)
3877b55e8cSThomas Abraham val |= PHY_CON16_ZQ_MODE_NOTERM_MASK;
3977b55e8cSThomas Abraham writel(val, phy0_con16);
4077b55e8cSThomas Abraham writel(val, phy1_con16);
4177b55e8cSThomas Abraham
4277b55e8cSThomas Abraham /* ZQ_MANUAL_START: Enable */
4377b55e8cSThomas Abraham val |= ZQ_MANUAL_STR;
4477b55e8cSThomas Abraham writel(val, phy0_con16);
4577b55e8cSThomas Abraham writel(val, phy1_con16);
4677b55e8cSThomas Abraham
4777b55e8cSThomas Abraham /* ZQ_MANUAL_START: Disable */
4877b55e8cSThomas Abraham val &= ~ZQ_MANUAL_STR;
4977b55e8cSThomas Abraham
5077b55e8cSThomas Abraham /*
5177b55e8cSThomas Abraham * Since we are manaully calibrating the ZQ values,
5277b55e8cSThomas Abraham * we are looping for the ZQ_init to complete.
5377b55e8cSThomas Abraham */
5477b55e8cSThomas Abraham i = ZQ_INIT_TIMEOUT;
5577b55e8cSThomas Abraham while ((readl(phy0_con17) & ZQ_DONE) != ZQ_DONE && i > 0) {
5677b55e8cSThomas Abraham sdelay(100);
5777b55e8cSThomas Abraham i--;
5877b55e8cSThomas Abraham }
5977b55e8cSThomas Abraham if (!i)
6077b55e8cSThomas Abraham return -1;
6177b55e8cSThomas Abraham writel(val, phy0_con16);
6277b55e8cSThomas Abraham
6377b55e8cSThomas Abraham i = ZQ_INIT_TIMEOUT;
6477b55e8cSThomas Abraham while ((readl(phy1_con17) & ZQ_DONE) != ZQ_DONE && i > 0) {
6577b55e8cSThomas Abraham sdelay(100);
6677b55e8cSThomas Abraham i--;
6777b55e8cSThomas Abraham }
6877b55e8cSThomas Abraham if (!i)
6977b55e8cSThomas Abraham return -1;
7077b55e8cSThomas Abraham writel(val, phy1_con16);
7177b55e8cSThomas Abraham
7277b55e8cSThomas Abraham return 0;
7377b55e8cSThomas Abraham }
7477b55e8cSThomas Abraham
update_reset_dll(uint32_t * phycontrol0,enum ddr_mode mode)7577b55e8cSThomas Abraham void update_reset_dll(uint32_t *phycontrol0, enum ddr_mode mode)
7677b55e8cSThomas Abraham {
7777b55e8cSThomas Abraham unsigned long val;
7877b55e8cSThomas Abraham
7977b55e8cSThomas Abraham if (mode == DDR_MODE_DDR3) {
8077b55e8cSThomas Abraham val = MEM_TERM_EN | PHY_TERM_EN | DMC_CTRL_SHGATE;
8177b55e8cSThomas Abraham writel(val, phycontrol0);
8277b55e8cSThomas Abraham }
8377b55e8cSThomas Abraham
8477b55e8cSThomas Abraham /* Update DLL Information: Force DLL Resyncronization */
8577b55e8cSThomas Abraham val = readl(phycontrol0);
8677b55e8cSThomas Abraham val |= FP_RSYNC;
8777b55e8cSThomas Abraham writel(val, phycontrol0);
8877b55e8cSThomas Abraham
8977b55e8cSThomas Abraham /* Reset Force DLL Resyncronization */
9077b55e8cSThomas Abraham val = readl(phycontrol0);
9177b55e8cSThomas Abraham val &= ~FP_RSYNC;
9277b55e8cSThomas Abraham writel(val, phycontrol0);
9377b55e8cSThomas Abraham }
9477b55e8cSThomas Abraham
dmc_config_mrs(struct mem_timings * mem,uint32_t * directcmd)9577b55e8cSThomas Abraham void dmc_config_mrs(struct mem_timings *mem, uint32_t *directcmd)
9677b55e8cSThomas Abraham {
9777b55e8cSThomas Abraham int channel, chip;
9877b55e8cSThomas Abraham
9977b55e8cSThomas Abraham for (channel = 0; channel < mem->dmc_channels; channel++) {
10077b55e8cSThomas Abraham unsigned long mask;
10177b55e8cSThomas Abraham
10277b55e8cSThomas Abraham mask = channel << DIRECT_CMD_CHANNEL_SHIFT;
10377b55e8cSThomas Abraham for (chip = 0; chip < mem->chips_to_configure; chip++) {
10477b55e8cSThomas Abraham int i;
10577b55e8cSThomas Abraham
10677b55e8cSThomas Abraham mask |= chip << DIRECT_CMD_CHIP_SHIFT;
10777b55e8cSThomas Abraham
10877b55e8cSThomas Abraham /* Sending NOP command */
10977b55e8cSThomas Abraham writel(DIRECT_CMD_NOP | mask, directcmd);
11077b55e8cSThomas Abraham
11177b55e8cSThomas Abraham /*
11277b55e8cSThomas Abraham * TODO(alim.akhtar@samsung.com): Do we need these
11377b55e8cSThomas Abraham * delays? This one and the next were not there for
11477b55e8cSThomas Abraham * DDR3.
11577b55e8cSThomas Abraham */
11677b55e8cSThomas Abraham sdelay(0x10000);
11777b55e8cSThomas Abraham
11877b55e8cSThomas Abraham /* Sending EMRS/MRS commands */
11977b55e8cSThomas Abraham for (i = 0; i < MEM_TIMINGS_MSR_COUNT; i++) {
12077b55e8cSThomas Abraham writel(mem->direct_cmd_msr[i] | mask,
12177b55e8cSThomas Abraham directcmd);
12277b55e8cSThomas Abraham sdelay(0x10000);
12377b55e8cSThomas Abraham }
12477b55e8cSThomas Abraham
12577b55e8cSThomas Abraham if (mem->send_zq_init) {
12677b55e8cSThomas Abraham /* Sending ZQINIT command */
12777b55e8cSThomas Abraham writel(DIRECT_CMD_ZQINIT | mask,
12877b55e8cSThomas Abraham directcmd);
12977b55e8cSThomas Abraham
13077b55e8cSThomas Abraham sdelay(10000);
13177b55e8cSThomas Abraham }
13277b55e8cSThomas Abraham }
13377b55e8cSThomas Abraham }
13477b55e8cSThomas Abraham }
13577b55e8cSThomas Abraham
dmc_config_prech(struct mem_timings * mem,uint32_t * directcmd)13677b55e8cSThomas Abraham void dmc_config_prech(struct mem_timings *mem, uint32_t *directcmd)
13777b55e8cSThomas Abraham {
13877b55e8cSThomas Abraham int channel, chip;
13977b55e8cSThomas Abraham
14077b55e8cSThomas Abraham for (channel = 0; channel < mem->dmc_channels; channel++) {
14177b55e8cSThomas Abraham unsigned long mask;
14277b55e8cSThomas Abraham
14377b55e8cSThomas Abraham mask = channel << DIRECT_CMD_CHANNEL_SHIFT;
14477b55e8cSThomas Abraham for (chip = 0; chip < mem->chips_per_channel; chip++) {
14577b55e8cSThomas Abraham mask |= chip << DIRECT_CMD_CHIP_SHIFT;
14677b55e8cSThomas Abraham
14777b55e8cSThomas Abraham /* PALL (all banks precharge) CMD */
14877b55e8cSThomas Abraham writel(DIRECT_CMD_PALL | mask, directcmd);
14977b55e8cSThomas Abraham sdelay(0x10000);
15077b55e8cSThomas Abraham }
15177b55e8cSThomas Abraham }
15277b55e8cSThomas Abraham }
15377b55e8cSThomas Abraham
mem_ctrl_init(int reset)15477b55e8cSThomas Abraham void mem_ctrl_init(int reset)
15577b55e8cSThomas Abraham {
15677b55e8cSThomas Abraham struct spl_machine_param *param = spl_get_machine_params();
15777b55e8cSThomas Abraham struct mem_timings *mem;
15877b55e8cSThomas Abraham int ret;
15977b55e8cSThomas Abraham
16077b55e8cSThomas Abraham mem = clock_get_mem_timings();
16177b55e8cSThomas Abraham
16277b55e8cSThomas Abraham /* If there are any other memory variant, add their init call below */
16377b55e8cSThomas Abraham if (param->mem_type == DDR_MODE_DDR3) {
16477b55e8cSThomas Abraham ret = ddr3_mem_ctrl_init(mem, reset);
16577b55e8cSThomas Abraham if (ret) {
16677b55e8cSThomas Abraham /* will hang if failed to init memory control */
16777b55e8cSThomas Abraham while (1)
16877b55e8cSThomas Abraham ;
16977b55e8cSThomas Abraham }
17077b55e8cSThomas Abraham } else {
17177b55e8cSThomas Abraham /* will hang if unknow memory type */
17277b55e8cSThomas Abraham while (1)
17377b55e8cSThomas Abraham ;
17477b55e8cSThomas Abraham }
17577b55e8cSThomas Abraham }
176