1 /*
2 * Copyright 2020-2023, 2025-2026 NXP
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6 #include <assert.h>
7
8 #include <ddr_init.h>
9
10 static uint32_t load_phy_image(uint32_t start_addr, size_t size,
11 const uint16_t image[]);
12
13 /* Load DDR configuration from given address and populate ddrss struct */
load_ddr_config(uintptr_t load_from)14 static struct ddrss_config load_ddr_config(uintptr_t load_from)
15 {
16 struct ddrss_config config;
17 struct ddr_fw_layout ddr_layout;
18 uintptr_t current_addr = load_from;
19
20 ddr_layout = *(struct ddr_fw_layout *)load_from;
21 current_addr += sizeof(struct ddr_fw_layout);
22
23 config.memory_type = ddr_layout.memory_type;
24 config.frequency = ddr_layout.frequency;
25 config.ddrc_size = ddr_layout.ddrc_size;
26 config.dq_swap_size = ddr_layout.dq_swap_size;
27 config.phy_size = ddr_layout.phy_size;
28 config.pie_size = ddr_layout.pie_size;
29 config.imem_1d_size = ddr_layout.imem_1d_size;
30 config.dmem_1d_size = ddr_layout.dmem_1d_size;
31 config.imem_2d_size = ddr_layout.imem_2d_size;
32 config.dmem_2d_size = ddr_layout.dmem_2d_size;
33 config.phy_csr_size = ddr_layout.phy_csr_size;
34 config.ddrc_csr_size = ddr_layout.ddrc_csr_size;
35
36 config.ddrc = (struct regconf *)(current_addr + ddr_layout.ddrc_offset);
37 config.dq_swap = (struct dqconf *)(current_addr + ddr_layout.dq_swap_offset);
38 config.phy = (struct regconf_16 *)(current_addr + ddr_layout.phy_offset);
39 config.pie = (struct regconf_16 *)(current_addr + ddr_layout.pie_offset);
40 config.imem_1d = (uint16_t *)(current_addr + ddr_layout.imem_1d_offset);
41 config.dmem_1d = (uint16_t *)(current_addr + ddr_layout.dmem_1d_offset);
42 config.imem_2d = (uint16_t *)(current_addr + ddr_layout.imem_2d_offset);
43 config.dmem_2d = (uint16_t *)(current_addr + ddr_layout.dmem_2d_offset);
44 config.phy_csr = (uint32_t *)(current_addr + ddr_layout.phy_csr_offset);
45 config.ddrc_csr = (uint32_t *)(current_addr + ddr_layout.ddrc_csr_offset);
46
47 return config;
48 }
49
50 /* Initialize ddr controller with given settings. */
ddrc_init_cfg(const struct ddrss_config * config)51 static uint32_t ddrc_init_cfg(const struct ddrss_config *config)
52 {
53 return load_register_cfg(config->ddrc_size, config->ddrc);
54 }
55
56 /* Main method needed to initialize ddr subsystem. */
ddr_init(uintptr_t load_from)57 uint32_t ddr_init(uintptr_t load_from)
58 {
59 struct ddrss_config ddr_config;
60 int err;
61
62 assert(load_from != 0UL);
63
64 err = plat_ddr_mmap_setup();
65 if (err != 0) {
66 return MAPPING_FAILED;
67 }
68
69 ddr_config = load_ddr_config(load_from + sizeof(struct ddr_fw_header));
70 return ddr_init_cfg(&ddr_config);
71 }
72
73 /* Execute 2D training stage if images are available */
execute_2d_training(const struct ddrss_config * config)74 static uint32_t execute_2d_training(const struct ddrss_config *config)
75 {
76 uint32_t ret = NO_ERR;
77
78 /* Load 2d imem image */
79 mmio_write_32(MICROCONT_MUX_SEL, UNLOCK_CSR_ACCESS);
80 ret = load_phy_image(IMEM_START_ADDR, config->imem_2d_size,
81 config->imem_2d);
82 if (ret != NO_ERR) {
83 return ret;
84 }
85 mmio_write_32(MICROCONT_MUX_SEL, LOCK_CSR_ACCESS);
86
87 /* Load 2d dmem image */
88 mmio_write_32(MICROCONT_MUX_SEL, UNLOCK_CSR_ACCESS);
89 ret = load_phy_image(DMEM_START_ADDR, config->dmem_2d_size,
90 config->dmem_2d);
91 if (ret != NO_ERR) {
92 return ret;
93 }
94
95 mmio_write_32(MICROCONT_MUX_SEL, LOCK_CSR_ACCESS);
96 mmio_write_32(APBONLY_MICRORESET, APBONLY_RESET_STALL_MASK);
97 mmio_write_32(APBONLY_MICRORESET, APBONLY_STALL_TO_MICRO_MASK);
98 mmio_write_32(APBONLY_MICRORESET, APBONLY_MICRORESET_CLR_MASK);
99
100 ret = wait_firmware_execution();
101 if (ret != NO_ERR) {
102 return ret;
103 }
104
105 /* Read 2D training results */
106 if (config->memory_type == (uint8_t)LPDDR4) {
107 mmio_write_32(MICROCONT_MUX_SEL, UNLOCK_CSR_ACCESS);
108 read_vref_dq();
109 compute_tphy_wrdata_delay();
110 mmio_write_32(MICROCONT_MUX_SEL, LOCK_CSR_ACCESS);
111 }
112
113 return ret;
114 }
115
116 /* Execute phy training with given settings. 2D training stage is optional. */
execute_training(const struct ddrss_config * config)117 static uint32_t execute_training(const struct ddrss_config *config)
118 {
119 uint32_t ret = NO_ERR;
120
121 /* Apply DQ swapping settings */
122 ret = load_dq_cfg(config->dq_swap_size, config->dq_swap);
123 if (ret != NO_ERR) {
124 return ret;
125 }
126
127 /* Initialize phy module */
128 ret = load_register_cfg_16(config->phy_size, config->phy);
129 if (ret != NO_ERR) {
130 return ret;
131 }
132
133 /* Configure PLL optimal settings */
134 set_optimal_pll(config->frequency);
135
136 /* Load 1D imem image */
137 mmio_write_32(MICROCONT_MUX_SEL, UNLOCK_CSR_ACCESS);
138 ret = load_phy_image(IMEM_START_ADDR, config->imem_1d_size,
139 config->imem_1d);
140 if (ret != NO_ERR) {
141 return ret;
142 }
143 mmio_write_32(MICROCONT_MUX_SEL, LOCK_CSR_ACCESS);
144
145 /* Load 1D dmem image */
146 mmio_write_32(MICROCONT_MUX_SEL, UNLOCK_CSR_ACCESS);
147 ret = load_phy_image(DMEM_START_ADDR, config->dmem_1d_size,
148 config->dmem_1d);
149 if (ret != NO_ERR) {
150 return ret;
151 }
152
153 mmio_write_32(MICROCONT_MUX_SEL, LOCK_CSR_ACCESS);
154 mmio_write_32(APBONLY_MICRORESET, APBONLY_RESET_STALL_MASK);
155 mmio_write_32(APBONLY_MICRORESET, APBONLY_STALL_TO_MICRO_MASK);
156 mmio_write_32(APBONLY_MICRORESET, APBONLY_MICRORESET_CLR_MASK);
157
158 ret = wait_firmware_execution();
159 mmio_write_32(MICROCONT_MUX_SEL, UNLOCK_CSR_ACCESS);
160 if (ret != NO_ERR) {
161 return ret;
162 }
163
164 /* Read critical delay differences and training results */
165 mmio_write_32(MICROCONT_MUX_SEL, UNLOCK_CSR_ACCESS);
166 read_cdds();
167 if (config->memory_type == (uint8_t)LPDDR4) {
168 read_vref_ca();
169 }
170 if (config->memory_type == (uint8_t)DDR3L) {
171 compute_tphy_wrdata_delay();
172 }
173 mmio_write_32(MICROCONT_MUX_SEL, LOCK_CSR_ACCESS);
174
175 /*
176 * Check if 2d training images have been initialized before executing
177 * the second training stage.
178 */
179 if ((config->imem_2d_size > 0U) && (config->dmem_2d_size > 0U)) {
180 ret = execute_2d_training(config);
181 if (ret != NO_ERR) {
182 return ret;
183 }
184 }
185
186 mmio_write_32(MICROCONT_MUX_SEL, UNLOCK_CSR_ACCESS);
187 /* Load pie image after training has executed */
188 ret = load_register_cfg_16(config->pie_size, config->pie);
189 mmio_write_32(MICROCONT_MUX_SEL, LOCK_CSR_ACCESS);
190 return ret;
191 }
192
193 /* Initialize ddr based on input configuration */
ddr_init_cfg(const struct ddrss_config * config)194 uint32_t ddr_init_cfg(const struct ddrss_config *config)
195 {
196 uint32_t ret = NO_ERR;
197
198 /* Init DDR controller based on selected parameter values */
199 ret = ddrc_init_cfg(config);
200 if (ret != NO_ERR) {
201 return ret;
202 }
203
204 /* Setup AXI ports parity */
205 ret = set_axi_parity();
206 if (ret != NO_ERR) {
207 return ret;
208 }
209
210 /* Init PHY module */
211 ret = execute_training(config);
212 if (ret != NO_ERR) {
213 return ret;
214 }
215
216 /* Execute post training setup */
217 ret = post_train_setup((uint8_t)(ADJUST_DDRC_MASK));
218
219 return ret;
220 }
221
222 /* Load register array into memory. */
load_register_cfg_16(size_t size,const struct regconf_16 cfg[])223 uint32_t load_register_cfg_16(size_t size, const struct regconf_16 cfg[])
224 {
225 size_t i;
226
227 for (i = 0; i < size; i++) {
228 mmio_write_16((uintptr_t)cfg[i].addr, cfg[i].data);
229 }
230
231 return NO_ERR;
232 }
233
234 /* Load register array into memory. */
load_register_cfg(size_t size,const struct regconf cfg[])235 uint32_t load_register_cfg(size_t size, const struct regconf cfg[])
236 {
237 size_t i;
238
239 for (i = 0; i < size; i++) {
240 mmio_write_32((uintptr_t)cfg[i].addr, cfg[i].data);
241 }
242
243 return NO_ERR;
244 }
245
246 /* Load dq config array into memory. */
load_dq_cfg(size_t size,const struct dqconf cfg[])247 uint32_t load_dq_cfg(size_t size, const struct dqconf cfg[])
248 {
249 size_t i;
250
251 for (i = 0; i < size; i++) {
252 mmio_write_32((uintptr_t)cfg[i].addr, cfg[i].data);
253 }
254
255 return NO_ERR;
256 }
257
258 /* Load image into memory at consecutive addresses */
load_phy_image(uint32_t start_addr,size_t size,const uint16_t image[])259 static uint32_t load_phy_image(uint32_t start_addr, size_t size,
260 const uint16_t image[])
261 {
262 uint32_t current_addr = start_addr;
263 size_t i;
264
265 for (i = 0; i < size; i++) {
266 mmio_write_32((uintptr_t)current_addr, image[i]);
267 current_addr += (uint32_t)sizeof(uint32_t);
268 }
269 return NO_ERR;
270 }
271
272 /* Ensure optimal phy pll settings for selected frequency. */
set_optimal_pll(uint16_t frequency)273 void set_optimal_pll(uint16_t frequency)
274 {
275 /* Configure phy pll registers */
276 mmio_write_32(MASTER_PLLCTRL1, PLLCTRL1_VALUE);
277 mmio_write_32(MASTER_PLLTESTMODE, PLLTESTMODE_VALUE);
278 mmio_write_32(MASTER_PLLCTRL4, PLLCTRL4_VALUE);
279 mmio_write_32(MASTER_PLLCTRL2, pllctrl2_value(frequency));
280
281 mmio_setbits_32(MASTER_CALMISC2, (CALMISC2 << CALMISC2_OFFSET));
282
283 mmio_clrsetbits_32(MASTER_CALOFFSET,
284 CALDRV_MASK, ((CALDRV << CALDRV_OFFSET) | (CALDRV << CALDRV2_OFFSET)));
285 }
286