• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018-2019, STMicroelectronics - All Rights Reserved
3  *
4  * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
5  */
6 
7 #include <errno.h>
8 
9 #include <libfdt.h>
10 
11 #include <platform_def.h>
12 
13 #include <arch_helpers.h>
14 #include <common/debug.h>
15 #include <drivers/st/stm32mp1_ddr.h>
16 #include <drivers/st/stm32mp1_ddr_helpers.h>
17 #include <drivers/st/stm32mp1_ram.h>
18 #include <lib/mmio.h>
19 
20 #define DDR_PATTERN	0xAAAAAAAAU
21 #define DDR_ANTIPATTERN	0x55555555U
22 
23 static struct ddr_info ddr_priv_data;
24 
stm32mp1_ddr_clk_enable(struct ddr_info * priv,uint32_t mem_speed)25 int stm32mp1_ddr_clk_enable(struct ddr_info *priv, uint32_t mem_speed)
26 {
27 	unsigned long ddrphy_clk, ddr_clk, mem_speed_hz;
28 
29 	ddr_enable_clock();
30 
31 	ddrphy_clk = stm32mp_clk_get_rate(DDRPHYC);
32 
33 	VERBOSE("DDR: mem_speed (%d kHz), RCC %ld kHz\n",
34 		mem_speed, ddrphy_clk / 1000U);
35 
36 	mem_speed_hz = mem_speed * 1000U;
37 
38 	/* Max 10% frequency delta */
39 	if (ddrphy_clk > mem_speed_hz) {
40 		ddr_clk = ddrphy_clk - mem_speed_hz;
41 	} else {
42 		ddr_clk = mem_speed_hz - ddrphy_clk;
43 	}
44 	if (ddr_clk > (mem_speed_hz / 10)) {
45 		ERROR("DDR expected freq %d kHz, current is %ld kHz\n",
46 		      mem_speed, ddrphy_clk / 1000U);
47 		return -1;
48 	}
49 	return 0;
50 }
51 
52 /*******************************************************************************
53  * This function tests the DDR data bus wiring.
54  * This is inspired from the Data Bus Test algorithm written by Michael Barr
55  * in "Programming Embedded Systems in C and C++" book.
56  * resources.oreilly.com/examples/9781565923546/blob/master/Chapter6/
57  * File: memtest.c - This source code belongs to Public Domain.
58  * Returns 0 if success, and address value else.
59  ******************************************************************************/
ddr_test_data_bus(void)60 static uint32_t ddr_test_data_bus(void)
61 {
62 	uint32_t pattern;
63 
64 	for (pattern = 1U; pattern != 0U; pattern <<= 1) {
65 		mmio_write_32(STM32MP_DDR_BASE, pattern);
66 
67 		if (mmio_read_32(STM32MP_DDR_BASE) != pattern) {
68 			return (uint32_t)STM32MP_DDR_BASE;
69 		}
70 	}
71 
72 	return 0;
73 }
74 
75 /*******************************************************************************
76  * This function tests the DDR address bus wiring.
77  * This is inspired from the Data Bus Test algorithm written by Michael Barr
78  * in "Programming Embedded Systems in C and C++" book.
79  * resources.oreilly.com/examples/9781565923546/blob/master/Chapter6/
80  * File: memtest.c - This source code belongs to Public Domain.
81  * Returns 0 if success, and address value else.
82  ******************************************************************************/
ddr_test_addr_bus(void)83 static uint32_t ddr_test_addr_bus(void)
84 {
85 	uint64_t addressmask = (ddr_priv_data.info.size - 1U);
86 	uint64_t offset;
87 	uint64_t testoffset = 0;
88 
89 	/* Write the default pattern at each of the power-of-two offsets. */
90 	for (offset = sizeof(uint32_t); (offset & addressmask) != 0U;
91 	     offset <<= 1) {
92 		mmio_write_32(STM32MP_DDR_BASE + (uint32_t)offset,
93 			      DDR_PATTERN);
94 	}
95 
96 	/* Check for address bits stuck high. */
97 	mmio_write_32(STM32MP_DDR_BASE + (uint32_t)testoffset,
98 		      DDR_ANTIPATTERN);
99 
100 	for (offset = sizeof(uint32_t); (offset & addressmask) != 0U;
101 	     offset <<= 1) {
102 		if (mmio_read_32(STM32MP_DDR_BASE + (uint32_t)offset) !=
103 		    DDR_PATTERN) {
104 			return (uint32_t)(STM32MP_DDR_BASE + offset);
105 		}
106 	}
107 
108 	mmio_write_32(STM32MP_DDR_BASE + (uint32_t)testoffset, DDR_PATTERN);
109 
110 	/* Check for address bits stuck low or shorted. */
111 	for (testoffset = sizeof(uint32_t); (testoffset & addressmask) != 0U;
112 	     testoffset <<= 1) {
113 		mmio_write_32(STM32MP_DDR_BASE + (uint32_t)testoffset,
114 			      DDR_ANTIPATTERN);
115 
116 		if (mmio_read_32(STM32MP_DDR_BASE) != DDR_PATTERN) {
117 			return STM32MP_DDR_BASE;
118 		}
119 
120 		for (offset = sizeof(uint32_t); (offset & addressmask) != 0U;
121 		     offset <<= 1) {
122 			if ((mmio_read_32(STM32MP_DDR_BASE +
123 					  (uint32_t)offset) != DDR_PATTERN) &&
124 			    (offset != testoffset)) {
125 				return (uint32_t)(STM32MP_DDR_BASE + offset);
126 			}
127 		}
128 
129 		mmio_write_32(STM32MP_DDR_BASE + (uint32_t)testoffset,
130 			      DDR_PATTERN);
131 	}
132 
133 	return 0;
134 }
135 
136 /*******************************************************************************
137  * This function checks the DDR size. It has to be run with Data Cache off.
138  * This test is run before data have been put in DDR, and is only done for
139  * cold boot. The DDR data can then be overwritten, and it is not useful to
140  * restore its content.
141  * Returns DDR computed size.
142  ******************************************************************************/
ddr_check_size(void)143 static uint32_t ddr_check_size(void)
144 {
145 	uint32_t offset = sizeof(uint32_t);
146 
147 	mmio_write_32(STM32MP_DDR_BASE, DDR_PATTERN);
148 
149 	while (offset < STM32MP_DDR_MAX_SIZE) {
150 		mmio_write_32(STM32MP_DDR_BASE + offset, DDR_ANTIPATTERN);
151 		dsb();
152 
153 		if (mmio_read_32(STM32MP_DDR_BASE) != DDR_PATTERN) {
154 			break;
155 		}
156 
157 		offset <<= 1;
158 	}
159 
160 	INFO("Memory size = 0x%x (%d MB)\n", offset, offset / (1024U * 1024U));
161 
162 	return offset;
163 }
164 
stm32mp1_ddr_setup(void)165 static int stm32mp1_ddr_setup(void)
166 {
167 	struct ddr_info *priv = &ddr_priv_data;
168 	int ret;
169 	struct stm32mp1_ddr_config config;
170 	int node, len;
171 	uint32_t uret, idx;
172 	void *fdt;
173 
174 #define PARAM(x, y)							\
175 	{								\
176 		.name = x,						\
177 		.offset = offsetof(struct stm32mp1_ddr_config, y),	\
178 		.size = sizeof(config.y) / sizeof(uint32_t)		\
179 	}
180 
181 #define CTL_PARAM(x) PARAM("st,ctl-"#x, c_##x)
182 #define PHY_PARAM(x) PARAM("st,phy-"#x, p_##x)
183 
184 	const struct {
185 		const char *name; /* Name in DT */
186 		const uint32_t offset; /* Offset in config struct */
187 		const uint32_t size;   /* Size of parameters */
188 	} param[] = {
189 		CTL_PARAM(reg),
190 		CTL_PARAM(timing),
191 		CTL_PARAM(map),
192 		CTL_PARAM(perf),
193 		PHY_PARAM(reg),
194 		PHY_PARAM(timing),
195 		PHY_PARAM(cal)
196 	};
197 
198 	if (fdt_get_address(&fdt) == 0) {
199 		return -ENOENT;
200 	}
201 
202 	node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT);
203 	if (node < 0) {
204 		ERROR("%s: Cannot read DDR node in DT\n", __func__);
205 		return -EINVAL;
206 	}
207 
208 	config.info.speed = fdt_read_uint32_default(node, "st,mem-speed", 0);
209 	if (!config.info.speed) {
210 		VERBOSE("%s: no st,mem-speed\n", __func__);
211 		return -EINVAL;
212 	}
213 	config.info.size = fdt_read_uint32_default(node, "st,mem-size", 0);
214 	if (!config.info.size) {
215 		VERBOSE("%s: no st,mem-size\n", __func__);
216 		return -EINVAL;
217 	}
218 	config.info.name = fdt_getprop(fdt, node, "st,mem-name", &len);
219 	if (config.info.name == NULL) {
220 		VERBOSE("%s: no st,mem-name\n", __func__);
221 		return -EINVAL;
222 	}
223 	INFO("RAM: %s\n", config.info.name);
224 
225 	for (idx = 0; idx < ARRAY_SIZE(param); idx++) {
226 		ret = fdt_read_uint32_array(node, param[idx].name,
227 					    (void *)((uintptr_t)&config +
228 						     param[idx].offset),
229 					    param[idx].size);
230 
231 		VERBOSE("%s: %s[0x%x] = %d\n", __func__,
232 			param[idx].name, param[idx].size, ret);
233 		if (ret != 0) {
234 			ERROR("%s: Cannot read %s\n",
235 			      __func__, param[idx].name);
236 			return -EINVAL;
237 		}
238 	}
239 
240 	/* Disable axidcg clock gating during init */
241 	mmio_clrbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_AXIDCGEN);
242 
243 	stm32mp1_ddr_init(priv, &config);
244 
245 	/* Enable axidcg clock gating */
246 	mmio_setbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_AXIDCGEN);
247 
248 	priv->info.size = config.info.size;
249 
250 	VERBOSE("%s : ram size(%x, %x)\n", __func__,
251 		(uint32_t)priv->info.base, (uint32_t)priv->info.size);
252 
253 	write_sctlr(read_sctlr() & ~SCTLR_C_BIT);
254 	dcsw_op_all(DC_OP_CISW);
255 
256 	uret = ddr_test_data_bus();
257 	if (uret != 0U) {
258 		ERROR("DDR data bus test: can't access memory @ 0x%x\n",
259 		      uret);
260 		panic();
261 	}
262 
263 	uret = ddr_test_addr_bus();
264 	if (uret != 0U) {
265 		ERROR("DDR addr bus test: can't access memory @ 0x%x\n",
266 		      uret);
267 		panic();
268 	}
269 
270 	uret = ddr_check_size();
271 	if (uret < config.info.size) {
272 		ERROR("DDR size: 0x%x does not match DT config: 0x%x\n",
273 		      uret, config.info.size);
274 		panic();
275 	}
276 
277 	write_sctlr(read_sctlr() | SCTLR_C_BIT);
278 
279 	return 0;
280 }
281 
stm32mp1_ddr_probe(void)282 int stm32mp1_ddr_probe(void)
283 {
284 	struct ddr_info *priv = &ddr_priv_data;
285 
286 	VERBOSE("STM32MP DDR probe\n");
287 
288 	priv->ctl = (struct stm32mp1_ddrctl *)stm32mp_ddrctrl_base();
289 	priv->phy = (struct stm32mp1_ddrphy *)stm32mp_ddrphyc_base();
290 	priv->pwr = stm32mp_pwr_base();
291 	priv->rcc = stm32mp_rcc_base();
292 
293 	priv->info.base = STM32MP_DDR_BASE;
294 	priv->info.size = 0;
295 
296 	return stm32mp1_ddr_setup();
297 }
298