14549e789STom Rini // SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
2e70f70aaSPatrick Delaunay /*
3e70f70aaSPatrick Delaunay  * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
4e70f70aaSPatrick Delaunay  */
5e70f70aaSPatrick Delaunay 
6e70f70aaSPatrick Delaunay #include <common.h>
7e70f70aaSPatrick Delaunay #include <clk.h>
8e70f70aaSPatrick Delaunay #include <dm.h>
9e70f70aaSPatrick Delaunay #include <ram.h>
10e70f70aaSPatrick Delaunay #include <regmap.h>
11e70f70aaSPatrick Delaunay #include <syscon.h>
12e70f70aaSPatrick Delaunay #include <asm/io.h>
13e70f70aaSPatrick Delaunay #include "stm32mp1_ddr.h"
14e70f70aaSPatrick Delaunay 
15e70f70aaSPatrick Delaunay static const char *const clkname[] = {
16e70f70aaSPatrick Delaunay 	"ddrc1",
17e70f70aaSPatrick Delaunay 	"ddrc2",
18e70f70aaSPatrick Delaunay 	"ddrcapb",
19e70f70aaSPatrick Delaunay 	"ddrphycapb",
20e70f70aaSPatrick Delaunay 	"ddrphyc" /* LAST clock => used for get_rate() */
21e70f70aaSPatrick Delaunay };
22e70f70aaSPatrick Delaunay 
stm32mp1_ddr_clk_enable(struct ddr_info * priv,uint16_t mem_speed)23e70f70aaSPatrick Delaunay int stm32mp1_ddr_clk_enable(struct ddr_info *priv, uint16_t mem_speed)
24e70f70aaSPatrick Delaunay {
25e70f70aaSPatrick Delaunay 	unsigned long ddrphy_clk;
26e70f70aaSPatrick Delaunay 	unsigned long ddr_clk;
27e70f70aaSPatrick Delaunay 	struct clk clk;
28e70f70aaSPatrick Delaunay 	int ret;
29e70f70aaSPatrick Delaunay 	int idx;
30e70f70aaSPatrick Delaunay 
31e70f70aaSPatrick Delaunay 	for (idx = 0; idx < ARRAY_SIZE(clkname); idx++) {
32e70f70aaSPatrick Delaunay 		ret = clk_get_by_name(priv->dev, clkname[idx], &clk);
33e70f70aaSPatrick Delaunay 
34e70f70aaSPatrick Delaunay 		if (!ret)
35e70f70aaSPatrick Delaunay 			ret = clk_enable(&clk);
36e70f70aaSPatrick Delaunay 
37e70f70aaSPatrick Delaunay 		if (ret) {
38e70f70aaSPatrick Delaunay 			printf("error for %s : %d\n", clkname[idx], ret);
39e70f70aaSPatrick Delaunay 			return ret;
40e70f70aaSPatrick Delaunay 		}
41e70f70aaSPatrick Delaunay 	}
42e70f70aaSPatrick Delaunay 
43e70f70aaSPatrick Delaunay 	priv->clk = clk;
44e70f70aaSPatrick Delaunay 	ddrphy_clk = clk_get_rate(&priv->clk);
45e70f70aaSPatrick Delaunay 
46e70f70aaSPatrick Delaunay 	debug("DDR: mem_speed (%d MHz), RCC %d MHz\n",
47e70f70aaSPatrick Delaunay 	      mem_speed, (u32)(ddrphy_clk / 1000 / 1000));
48e70f70aaSPatrick Delaunay 	/* max 10% frequency delta */
49e70f70aaSPatrick Delaunay 	ddr_clk = abs(ddrphy_clk - mem_speed * 1000 * 1000);
50e70f70aaSPatrick Delaunay 	if (ddr_clk > (mem_speed * 1000 * 100)) {
51e70f70aaSPatrick Delaunay 		pr_err("DDR expected freq %d MHz, current is %d MHz\n",
52e70f70aaSPatrick Delaunay 		       mem_speed, (u32)(ddrphy_clk / 1000 / 1000));
53e70f70aaSPatrick Delaunay 		return -EINVAL;
54e70f70aaSPatrick Delaunay 	}
55e70f70aaSPatrick Delaunay 
56e70f70aaSPatrick Delaunay 	return 0;
57e70f70aaSPatrick Delaunay }
58e70f70aaSPatrick Delaunay 
stm32mp1_ddr_setup(struct udevice * dev)59e70f70aaSPatrick Delaunay static __maybe_unused int stm32mp1_ddr_setup(struct udevice *dev)
60e70f70aaSPatrick Delaunay {
61e70f70aaSPatrick Delaunay 	struct ddr_info *priv = dev_get_priv(dev);
62e70f70aaSPatrick Delaunay 	int ret, idx;
63e70f70aaSPatrick Delaunay 	struct clk axidcg;
64e70f70aaSPatrick Delaunay 	struct stm32mp1_ddr_config config;
65e70f70aaSPatrick Delaunay 
66e70f70aaSPatrick Delaunay #define PARAM(x, y) \
67e70f70aaSPatrick Delaunay 	{ x,\
68e70f70aaSPatrick Delaunay 	  offsetof(struct stm32mp1_ddr_config, y),\
69e70f70aaSPatrick Delaunay 	  sizeof(config.y) / sizeof(u32)}
70e70f70aaSPatrick Delaunay 
71e70f70aaSPatrick Delaunay #define CTL_PARAM(x) PARAM("st,ctl-"#x, c_##x)
72e70f70aaSPatrick Delaunay #define PHY_PARAM(x) PARAM("st,phy-"#x, p_##x)
73e70f70aaSPatrick Delaunay 
74e70f70aaSPatrick Delaunay 	const struct {
75e70f70aaSPatrick Delaunay 		const char *name; /* name in DT */
76e70f70aaSPatrick Delaunay 		const u32 offset; /* offset in config struct */
77e70f70aaSPatrick Delaunay 		const u32 size;   /* size of parameters */
78e70f70aaSPatrick Delaunay 	} param[] = {
79e70f70aaSPatrick Delaunay 		CTL_PARAM(reg),
80e70f70aaSPatrick Delaunay 		CTL_PARAM(timing),
81e70f70aaSPatrick Delaunay 		CTL_PARAM(map),
82e70f70aaSPatrick Delaunay 		CTL_PARAM(perf),
83e70f70aaSPatrick Delaunay 		PHY_PARAM(reg),
84e70f70aaSPatrick Delaunay 		PHY_PARAM(timing),
85e70f70aaSPatrick Delaunay 		PHY_PARAM(cal)
86e70f70aaSPatrick Delaunay 	};
87e70f70aaSPatrick Delaunay 
88e70f70aaSPatrick Delaunay 	config.info.speed = dev_read_u32_default(dev, "st,mem-speed", 0);
89e70f70aaSPatrick Delaunay 	config.info.size = dev_read_u32_default(dev, "st,mem-size", 0);
90e70f70aaSPatrick Delaunay 	config.info.name = dev_read_string(dev, "st,mem-name");
91e70f70aaSPatrick Delaunay 	if (!config.info.name) {
92e70f70aaSPatrick Delaunay 		debug("%s: no st,mem-name\n", __func__);
93e70f70aaSPatrick Delaunay 		return -EINVAL;
94e70f70aaSPatrick Delaunay 	}
95e70f70aaSPatrick Delaunay 	printf("RAM: %s\n", config.info.name);
96e70f70aaSPatrick Delaunay 
97e70f70aaSPatrick Delaunay 	for (idx = 0; idx < ARRAY_SIZE(param); idx++) {
98e70f70aaSPatrick Delaunay 		ret = dev_read_u32_array(dev, param[idx].name,
99e70f70aaSPatrick Delaunay 					 (void *)((u32)&config +
100e70f70aaSPatrick Delaunay 						  param[idx].offset),
101e70f70aaSPatrick Delaunay 					 param[idx].size);
102e70f70aaSPatrick Delaunay 		debug("%s: %s[0x%x] = %d\n", __func__,
103e70f70aaSPatrick Delaunay 		      param[idx].name, param[idx].size, ret);
104e70f70aaSPatrick Delaunay 		if (ret) {
105e70f70aaSPatrick Delaunay 			pr_err("%s: Cannot read %s\n",
106e70f70aaSPatrick Delaunay 			       __func__, param[idx].name);
107e70f70aaSPatrick Delaunay 			return -EINVAL;
108e70f70aaSPatrick Delaunay 		}
109e70f70aaSPatrick Delaunay 	}
110e70f70aaSPatrick Delaunay 
111e70f70aaSPatrick Delaunay 	ret = clk_get_by_name(dev, "axidcg", &axidcg);
112e70f70aaSPatrick Delaunay 	if (ret) {
113e70f70aaSPatrick Delaunay 		debug("%s: Cannot found axidcg\n", __func__);
114e70f70aaSPatrick Delaunay 		return -EINVAL;
115e70f70aaSPatrick Delaunay 	}
116e70f70aaSPatrick Delaunay 	clk_disable(&axidcg); /* disable clock gating during init */
117e70f70aaSPatrick Delaunay 
118e70f70aaSPatrick Delaunay 	stm32mp1_ddr_init(priv, &config);
119e70f70aaSPatrick Delaunay 
120e70f70aaSPatrick Delaunay 	clk_enable(&axidcg); /* enable clock gating */
121e70f70aaSPatrick Delaunay 
122e70f70aaSPatrick Delaunay 	/* check size */
123e70f70aaSPatrick Delaunay 	debug("%s : get_ram_size(%x, %x)\n", __func__,
124e70f70aaSPatrick Delaunay 	      (u32)priv->info.base, (u32)STM32_DDR_SIZE);
125e70f70aaSPatrick Delaunay 
126e70f70aaSPatrick Delaunay 	priv->info.size = get_ram_size((long *)priv->info.base,
127e70f70aaSPatrick Delaunay 				       STM32_DDR_SIZE);
128e70f70aaSPatrick Delaunay 
129e70f70aaSPatrick Delaunay 	debug("%s : %x\n", __func__, (u32)priv->info.size);
130e70f70aaSPatrick Delaunay 
131e70f70aaSPatrick Delaunay 	/* check memory access for all memory */
132e70f70aaSPatrick Delaunay 	if (config.info.size != priv->info.size) {
133e70f70aaSPatrick Delaunay 		printf("DDR invalid size : 0x%x, expected 0x%x\n",
134e70f70aaSPatrick Delaunay 		       priv->info.size, config.info.size);
135e70f70aaSPatrick Delaunay 		return -EINVAL;
136e70f70aaSPatrick Delaunay 	}
137e70f70aaSPatrick Delaunay 	return 0;
138e70f70aaSPatrick Delaunay }
139e70f70aaSPatrick Delaunay 
stm32mp1_ddr_probe(struct udevice * dev)140e70f70aaSPatrick Delaunay static int stm32mp1_ddr_probe(struct udevice *dev)
141e70f70aaSPatrick Delaunay {
142e70f70aaSPatrick Delaunay 	struct ddr_info *priv = dev_get_priv(dev);
143e70f70aaSPatrick Delaunay 	struct regmap *map;
144e70f70aaSPatrick Delaunay 	int ret;
145e70f70aaSPatrick Delaunay 
146e70f70aaSPatrick Delaunay 	debug("STM32MP1 DDR probe\n");
147e70f70aaSPatrick Delaunay 	priv->dev = dev;
148e70f70aaSPatrick Delaunay 
149*d3581236SMasahiro Yamada 	ret = regmap_init_mem(dev_ofnode(dev), &map);
150e70f70aaSPatrick Delaunay 	if (ret)
151e70f70aaSPatrick Delaunay 		return ret;
152e70f70aaSPatrick Delaunay 
153e70f70aaSPatrick Delaunay 	priv->ctl = regmap_get_range(map, 0);
154e70f70aaSPatrick Delaunay 	priv->phy = regmap_get_range(map, 1);
155e70f70aaSPatrick Delaunay 
156e70f70aaSPatrick Delaunay 	priv->rcc = STM32_RCC_BASE;
157e70f70aaSPatrick Delaunay 
158e70f70aaSPatrick Delaunay 	priv->info.base = STM32_DDR_BASE;
159e70f70aaSPatrick Delaunay 
160e70f70aaSPatrick Delaunay #if !defined(CONFIG_SPL) || defined(CONFIG_SPL_BUILD)
161e70f70aaSPatrick Delaunay 	priv->info.size = 0;
162e70f70aaSPatrick Delaunay 	return stm32mp1_ddr_setup(dev);
163e70f70aaSPatrick Delaunay #else
164e70f70aaSPatrick Delaunay 	priv->info.size = dev_read_u32_default(dev, "st,mem-size", 0);
165e70f70aaSPatrick Delaunay 	return 0;
166e70f70aaSPatrick Delaunay #endif
167e70f70aaSPatrick Delaunay }
168e70f70aaSPatrick Delaunay 
stm32mp1_ddr_get_info(struct udevice * dev,struct ram_info * info)169e70f70aaSPatrick Delaunay static int stm32mp1_ddr_get_info(struct udevice *dev, struct ram_info *info)
170e70f70aaSPatrick Delaunay {
171e70f70aaSPatrick Delaunay 	struct ddr_info *priv = dev_get_priv(dev);
172e70f70aaSPatrick Delaunay 
173e70f70aaSPatrick Delaunay 	*info = priv->info;
174e70f70aaSPatrick Delaunay 
175e70f70aaSPatrick Delaunay 	return 0;
176e70f70aaSPatrick Delaunay }
177e70f70aaSPatrick Delaunay 
178e70f70aaSPatrick Delaunay static struct ram_ops stm32mp1_ddr_ops = {
179e70f70aaSPatrick Delaunay 	.get_info = stm32mp1_ddr_get_info,
180e70f70aaSPatrick Delaunay };
181e70f70aaSPatrick Delaunay 
182e70f70aaSPatrick Delaunay static const struct udevice_id stm32mp1_ddr_ids[] = {
183e70f70aaSPatrick Delaunay 	{ .compatible = "st,stm32mp1-ddr" },
184e70f70aaSPatrick Delaunay 	{ }
185e70f70aaSPatrick Delaunay };
186e70f70aaSPatrick Delaunay 
187e70f70aaSPatrick Delaunay U_BOOT_DRIVER(ddr_stm32mp1) = {
188e70f70aaSPatrick Delaunay 	.name = "stm32mp1_ddr",
189e70f70aaSPatrick Delaunay 	.id = UCLASS_RAM,
190e70f70aaSPatrick Delaunay 	.of_match = stm32mp1_ddr_ids,
191e70f70aaSPatrick Delaunay 	.ops = &stm32mp1_ddr_ops,
192e70f70aaSPatrick Delaunay 	.probe = stm32mp1_ddr_probe,
193e70f70aaSPatrick Delaunay 	.priv_auto_alloc_size = sizeof(struct ddr_info),
194e70f70aaSPatrick Delaunay };
195