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