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