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