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