]>
Commit | Line | Data |
---|---|---|
e3963c09 PF |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | |
3 | * Copyright 2018 NXP | |
4 | */ | |
5 | ||
23387416 | 6 | #include <binman_sym.h> |
f7ae49fc | 7 | #include <log.h> |
e3963c09 | 8 | #include <spl.h> |
401d1c4f | 9 | #include <asm/global_data.h> |
e3963c09 PF |
10 | #include <asm/io.h> |
11 | #include <errno.h> | |
12 | #include <asm/io.h> | |
13 | #include <asm/arch/ddr.h> | |
14 | #include <asm/arch/ddr.h> | |
e3963c09 PF |
15 | #include <asm/sections.h> |
16 | ||
17 | DECLARE_GLOBAL_DATA_PTR; | |
18 | ||
19 | #define IMEM_LEN 32768 /* byte */ | |
20 | #define DMEM_LEN 16384 /* byte */ | |
21 | #define IMEM_2D_OFFSET 49152 | |
22 | ||
23 | #define IMEM_OFFSET_ADDR 0x00050000 | |
24 | #define DMEM_OFFSET_ADDR 0x00054000 | |
25 | #define DDR_TRAIN_CODE_BASE_ADDR IP2APB_DDRPHY_IPS_BASE_ADDR(0) | |
26 | ||
23387416 PF |
27 | binman_sym_declare(ulong, ddr_1d_imem_fw, image_pos); |
28 | binman_sym_declare(ulong, ddr_1d_imem_fw, size); | |
29 | ||
30 | binman_sym_declare(ulong, ddr_1d_dmem_fw, image_pos); | |
31 | binman_sym_declare(ulong, ddr_1d_dmem_fw, size); | |
32 | ||
33 | #if !IS_ENABLED(CONFIG_IMX8M_DDR3L) | |
34 | binman_sym_declare(ulong, ddr_2d_imem_fw, image_pos); | |
35 | binman_sym_declare(ulong, ddr_2d_imem_fw, size); | |
36 | ||
37 | binman_sym_declare(ulong, ddr_2d_dmem_fw, image_pos); | |
38 | binman_sym_declare(ulong, ddr_2d_dmem_fw, size); | |
39 | #endif | |
40 | ||
e3963c09 PF |
41 | /* We need PHY iMEM PHY is 32KB padded */ |
42 | void ddr_load_train_firmware(enum fw_type type) | |
43 | { | |
44 | u32 tmp32, i; | |
45 | u32 error = 0; | |
46 | unsigned long pr_to32, pr_from32; | |
23387416 | 47 | uint32_t fw_offset = type ? IMEM_2D_OFFSET : 0; |
ccea96f4 | 48 | unsigned long imem_start = (unsigned long)_end + fw_offset; |
28cb058f | 49 | unsigned long dmem_start; |
23387416 | 50 | unsigned long imem_len = IMEM_LEN, dmem_len = DMEM_LEN; |
b614ddb5 SG |
51 | static enum fw_type last_type = -1; |
52 | ||
53 | /* If FW doesn't change, we can save the loading. */ | |
54 | if (last_type == type) | |
55 | return; | |
56 | ||
57 | last_type = type; | |
28cb058f PF |
58 | |
59 | #ifdef CONFIG_SPL_OF_CONTROL | |
60 | if (gd->fdt_blob && !fdt_check_header(gd->fdt_blob)) { | |
ccea96f4 | 61 | imem_start = roundup((unsigned long)_end + |
28cb058f PF |
62 | fdt_totalsize(gd->fdt_blob), 4) + |
63 | fw_offset; | |
64 | } | |
65 | #endif | |
66 | ||
23387416 PF |
67 | dmem_start = imem_start + imem_len; |
68 | ||
69 | if (BINMAN_SYMS_OK) { | |
70 | switch (type) { | |
71 | case FW_1D_IMAGE: | |
72 | imem_start = binman_sym(ulong, ddr_1d_imem_fw, image_pos); | |
73 | imem_len = binman_sym(ulong, ddr_1d_imem_fw, size); | |
74 | dmem_start = binman_sym(ulong, ddr_1d_dmem_fw, image_pos); | |
75 | dmem_len = binman_sym(ulong, ddr_1d_dmem_fw, size); | |
76 | break; | |
77 | case FW_2D_IMAGE: | |
78 | #if !IS_ENABLED(CONFIG_IMX8M_DDR3L) | |
79 | imem_start = binman_sym(ulong, ddr_2d_imem_fw, image_pos); | |
80 | imem_len = binman_sym(ulong, ddr_2d_imem_fw, size); | |
81 | dmem_start = binman_sym(ulong, ddr_2d_dmem_fw, image_pos); | |
82 | dmem_len = binman_sym(ulong, ddr_2d_dmem_fw, size); | |
83 | #endif | |
84 | break; | |
85 | } | |
86 | } | |
e3963c09 PF |
87 | |
88 | pr_from32 = imem_start; | |
99c7cc58 | 89 | pr_to32 = IMEM_OFFSET_ADDR; |
23387416 | 90 | for (i = 0x0; i < imem_len; ) { |
e3963c09 | 91 | tmp32 = readl(pr_from32); |
99c7cc58 YL |
92 | writew(tmp32 & 0x0000ffff, DDR_TRAIN_CODE_BASE_ADDR + ddrphy_addr_remap(pr_to32)); |
93 | pr_to32 += 1; | |
94 | writew((tmp32 >> 16) & 0x0000ffff, | |
95 | DDR_TRAIN_CODE_BASE_ADDR + ddrphy_addr_remap(pr_to32)); | |
96 | pr_to32 += 1; | |
e3963c09 PF |
97 | pr_from32 += 4; |
98 | i += 4; | |
99 | } | |
100 | ||
101 | pr_from32 = dmem_start; | |
99c7cc58 | 102 | pr_to32 = DMEM_OFFSET_ADDR; |
23387416 | 103 | for (i = 0x0; i < dmem_len; ) { |
e3963c09 | 104 | tmp32 = readl(pr_from32); |
99c7cc58 YL |
105 | writew(tmp32 & 0x0000ffff, DDR_TRAIN_CODE_BASE_ADDR + ddrphy_addr_remap(pr_to32)); |
106 | pr_to32 += 1; | |
107 | writew((tmp32 >> 16) & 0x0000ffff, | |
108 | DDR_TRAIN_CODE_BASE_ADDR + ddrphy_addr_remap(pr_to32)); | |
109 | pr_to32 += 1; | |
e3963c09 PF |
110 | pr_from32 += 4; |
111 | i += 4; | |
112 | } | |
113 | ||
825ab6b4 | 114 | debug("check ddr_pmu_train_imem code\n"); |
e3963c09 | 115 | pr_from32 = imem_start; |
99c7cc58 | 116 | pr_to32 = IMEM_OFFSET_ADDR; |
23387416 | 117 | for (i = 0x0; i < imem_len; ) { |
99c7cc58 YL |
118 | tmp32 = (readw(DDR_TRAIN_CODE_BASE_ADDR + ddrphy_addr_remap(pr_to32)) & 0x0000ffff); |
119 | pr_to32 += 1; | |
120 | tmp32 += ((readw(DDR_TRAIN_CODE_BASE_ADDR + | |
121 | ddrphy_addr_remap(pr_to32)) & 0x0000ffff) << 16); | |
e3963c09 PF |
122 | |
123 | if (tmp32 != readl(pr_from32)) { | |
124 | debug("%lx %lx\n", pr_from32, pr_to32); | |
125 | error++; | |
126 | } | |
127 | pr_from32 += 4; | |
99c7cc58 | 128 | pr_to32 += 1; |
e3963c09 PF |
129 | i += 4; |
130 | } | |
131 | if (error) | |
825ab6b4 | 132 | printf("check ddr_pmu_train_imem code fail=%d\n", error); |
e3963c09 | 133 | else |
825ab6b4 | 134 | debug("check ddr_pmu_train_imem code pass\n"); |
e3963c09 PF |
135 | |
136 | debug("check ddr4_pmu_train_dmem code\n"); | |
137 | pr_from32 = dmem_start; | |
99c7cc58 | 138 | pr_to32 = DMEM_OFFSET_ADDR; |
23387416 | 139 | for (i = 0x0; i < dmem_len;) { |
99c7cc58 YL |
140 | tmp32 = (readw(DDR_TRAIN_CODE_BASE_ADDR + ddrphy_addr_remap(pr_to32)) & 0x0000ffff); |
141 | pr_to32 += 1; | |
142 | tmp32 += ((readw(DDR_TRAIN_CODE_BASE_ADDR + | |
143 | ddrphy_addr_remap(pr_to32)) & 0x0000ffff) << 16); | |
e3963c09 PF |
144 | if (tmp32 != readl(pr_from32)) { |
145 | debug("%lx %lx\n", pr_from32, pr_to32); | |
146 | error++; | |
147 | } | |
148 | pr_from32 += 4; | |
99c7cc58 | 149 | pr_to32 += 1; |
e3963c09 PF |
150 | i += 4; |
151 | } | |
152 | ||
153 | if (error) | |
825ab6b4 | 154 | printf("check ddr_pmu_train_dmem code fail=%d", error); |
e3963c09 | 155 | else |
825ab6b4 | 156 | debug("check ddr_pmu_train_dmem code pass\n"); |
e3963c09 PF |
157 | } |
158 | ||
159 | void ddrphy_trained_csr_save(struct dram_cfg_param *ddrphy_csr, | |
160 | unsigned int num) | |
161 | { | |
162 | int i = 0; | |
163 | ||
164 | /* enable the ddrphy apb */ | |
165 | dwc_ddrphy_apb_wr(0xd0000, 0x0); | |
166 | dwc_ddrphy_apb_wr(0xc0080, 0x3); | |
167 | for (i = 0; i < num; i++) { | |
168 | ddrphy_csr->val = dwc_ddrphy_apb_rd(ddrphy_csr->reg); | |
169 | ddrphy_csr++; | |
170 | } | |
171 | /* disable the ddrphy apb */ | |
172 | dwc_ddrphy_apb_wr(0xc0080, 0x2); | |
173 | dwc_ddrphy_apb_wr(0xd0000, 0x1); | |
174 | } | |
175 | ||
8e81e679 | 176 | void *dram_config_save(struct dram_timing_info *timing_info, unsigned long saved_timing_base) |
e3963c09 PF |
177 | { |
178 | int i = 0; | |
179 | struct dram_timing_info *saved_timing = (struct dram_timing_info *)saved_timing_base; | |
180 | struct dram_cfg_param *cfg; | |
181 | ||
182 | saved_timing->ddrc_cfg_num = timing_info->ddrc_cfg_num; | |
183 | saved_timing->ddrphy_cfg_num = timing_info->ddrphy_cfg_num; | |
6016960c | 184 | saved_timing->ddrphy_trained_csr_num = timing_info->ddrphy_trained_csr_num; |
e3963c09 PF |
185 | saved_timing->ddrphy_pie_num = timing_info->ddrphy_pie_num; |
186 | ||
187 | /* save the fsp table */ | |
188 | for (i = 0; i < 4; i++) | |
189 | saved_timing->fsp_table[i] = timing_info->fsp_table[i]; | |
190 | ||
191 | cfg = (struct dram_cfg_param *)(saved_timing_base + | |
192 | sizeof(*timing_info)); | |
193 | ||
194 | /* save ddrc config */ | |
195 | saved_timing->ddrc_cfg = cfg; | |
196 | for (i = 0; i < timing_info->ddrc_cfg_num; i++) { | |
197 | cfg->reg = timing_info->ddrc_cfg[i].reg; | |
198 | cfg->val = timing_info->ddrc_cfg[i].val; | |
199 | cfg++; | |
200 | } | |
201 | ||
202 | /* save ddrphy config */ | |
203 | saved_timing->ddrphy_cfg = cfg; | |
204 | for (i = 0; i < timing_info->ddrphy_cfg_num; i++) { | |
205 | cfg->reg = timing_info->ddrphy_cfg[i].reg; | |
206 | cfg->val = timing_info->ddrphy_cfg[i].val; | |
207 | cfg++; | |
208 | } | |
209 | ||
210 | /* save the ddrphy csr */ | |
211 | saved_timing->ddrphy_trained_csr = cfg; | |
6016960c PF |
212 | for (i = 0; i < timing_info->ddrphy_trained_csr_num; i++) { |
213 | cfg->reg = timing_info->ddrphy_trained_csr[i].reg; | |
214 | cfg->val = timing_info->ddrphy_trained_csr[i].val; | |
e3963c09 PF |
215 | cfg++; |
216 | } | |
217 | ||
218 | /* save the ddrphy pie */ | |
219 | saved_timing->ddrphy_pie = cfg; | |
220 | for (i = 0; i < timing_info->ddrphy_pie_num; i++) { | |
221 | cfg->reg = timing_info->ddrphy_pie[i].reg; | |
222 | cfg->val = timing_info->ddrphy_pie[i].val; | |
223 | cfg++; | |
224 | } | |
8e81e679 JB |
225 | |
226 | return (void *)cfg; | |
e3963c09 | 227 | } |