1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Mem setup common file for different types of DDR present on Exynos boards.
4  *
5  * Copyright (C) 2012 Samsung Electronics
6  */
7 
8 #include <common.h>
9 #include <asm/arch/spl.h>
10 
11 #include "clock_init.h"
12 #include "common_setup.h"
13 #include "exynos5_setup.h"
14 
15 #define ZQ_INIT_TIMEOUT	10000
16 
17 int dmc_config_zq(struct mem_timings *mem, uint32_t *phy0_con16,
18 			uint32_t *phy1_con16, uint32_t *phy0_con17,
19 			uint32_t *phy1_con17)
20 {
21 	unsigned long val = 0;
22 	int i;
23 
24 	/*
25 	 * ZQ Calibration:
26 	 * Select Driver Strength,
27 	 * long calibration for manual calibration
28 	 */
29 	val = PHY_CON16_RESET_VAL;
30 	val |= mem->zq_mode_dds << PHY_CON16_ZQ_MODE_DDS_SHIFT;
31 	val |= mem->zq_mode_term << PHY_CON16_ZQ_MODE_TERM_SHIFT;
32 	val |= ZQ_CLK_DIV_EN;
33 	writel(val, phy0_con16);
34 	writel(val, phy1_con16);
35 
36 	/* Disable termination */
37 	if (mem->zq_mode_noterm)
38 		val |= PHY_CON16_ZQ_MODE_NOTERM_MASK;
39 	writel(val, phy0_con16);
40 	writel(val, phy1_con16);
41 
42 	/* ZQ_MANUAL_START: Enable */
43 	val |= ZQ_MANUAL_STR;
44 	writel(val, phy0_con16);
45 	writel(val, phy1_con16);
46 
47 	/* ZQ_MANUAL_START: Disable */
48 	val &= ~ZQ_MANUAL_STR;
49 
50 	/*
51 	 * Since we are manaully calibrating the ZQ values,
52 	 * we are looping for the ZQ_init to complete.
53 	 */
54 	i = ZQ_INIT_TIMEOUT;
55 	while ((readl(phy0_con17) & ZQ_DONE) != ZQ_DONE && i > 0) {
56 		sdelay(100);
57 		i--;
58 	}
59 	if (!i)
60 		return -1;
61 	writel(val, phy0_con16);
62 
63 	i = ZQ_INIT_TIMEOUT;
64 	while ((readl(phy1_con17) & ZQ_DONE) != ZQ_DONE && i > 0) {
65 		sdelay(100);
66 		i--;
67 	}
68 	if (!i)
69 		return -1;
70 	writel(val, phy1_con16);
71 
72 	return 0;
73 }
74 
75 void update_reset_dll(uint32_t *phycontrol0, enum ddr_mode mode)
76 {
77 	unsigned long val;
78 
79 	if (mode == DDR_MODE_DDR3) {
80 		val = MEM_TERM_EN | PHY_TERM_EN | DMC_CTRL_SHGATE;
81 		writel(val, phycontrol0);
82 	}
83 
84 	/* Update DLL Information: Force DLL Resyncronization */
85 	val = readl(phycontrol0);
86 	val |= FP_RSYNC;
87 	writel(val, phycontrol0);
88 
89 	/* Reset Force DLL Resyncronization */
90 	val = readl(phycontrol0);
91 	val &= ~FP_RSYNC;
92 	writel(val, phycontrol0);
93 }
94 
95 void dmc_config_mrs(struct mem_timings *mem, uint32_t *directcmd)
96 {
97 	int channel, chip;
98 
99 	for (channel = 0; channel < mem->dmc_channels; channel++) {
100 		unsigned long mask;
101 
102 		mask = channel << DIRECT_CMD_CHANNEL_SHIFT;
103 		for (chip = 0; chip < mem->chips_to_configure; chip++) {
104 			int i;
105 
106 			mask |= chip << DIRECT_CMD_CHIP_SHIFT;
107 
108 			/* Sending NOP command */
109 			writel(DIRECT_CMD_NOP | mask, directcmd);
110 
111 			/*
112 			 * TODO(alim.akhtar@samsung.com): Do we need these
113 			 * delays? This one and the next were not there for
114 			 * DDR3.
115 			 */
116 			sdelay(0x10000);
117 
118 			/* Sending EMRS/MRS commands */
119 			for (i = 0; i < MEM_TIMINGS_MSR_COUNT; i++) {
120 				writel(mem->direct_cmd_msr[i] | mask,
121 				       directcmd);
122 				sdelay(0x10000);
123 			}
124 
125 			if (mem->send_zq_init) {
126 				/* Sending ZQINIT command */
127 				writel(DIRECT_CMD_ZQINIT | mask,
128 				       directcmd);
129 
130 				sdelay(10000);
131 			}
132 		}
133 	}
134 }
135 
136 void dmc_config_prech(struct mem_timings *mem, uint32_t *directcmd)
137 {
138 	int channel, chip;
139 
140 	for (channel = 0; channel < mem->dmc_channels; channel++) {
141 		unsigned long mask;
142 
143 		mask = channel << DIRECT_CMD_CHANNEL_SHIFT;
144 		for (chip = 0; chip < mem->chips_per_channel; chip++) {
145 			mask |= chip << DIRECT_CMD_CHIP_SHIFT;
146 
147 			/* PALL (all banks precharge) CMD */
148 			writel(DIRECT_CMD_PALL | mask, directcmd);
149 			sdelay(0x10000);
150 		}
151 	}
152 }
153 
154 void mem_ctrl_init(int reset)
155 {
156 	struct spl_machine_param *param = spl_get_machine_params();
157 	struct mem_timings *mem;
158 	int ret;
159 
160 	mem = clock_get_mem_timings();
161 
162 	/* If there are any other memory variant, add their init call below */
163 	if (param->mem_type == DDR_MODE_DDR3) {
164 		ret = ddr3_mem_ctrl_init(mem, reset);
165 		if (ret) {
166 			/* will hang if failed to init memory control */
167 			while (1)
168 				;
169 		}
170 	} else {
171 		/* will hang if unknow memory type  */
172 		while (1)
173 			;
174 	}
175 }
176