blob: 2cc05713a13da0bdba8a1c54d75ab6594f20af2f [file] [log] [blame]
Huayang Duanc90a9e62020-06-22 19:52:45 +08001/* SPDX-License-Identifier: GPL-2.0-only */
2
3#include <assert.h>
4#include <bootmode.h>
5#include <cbfs.h>
6#include <console/console.h>
7#include <ip_checksum.h>
8#include <soc/emi.h>
9#include <symbols.h>
Huayang Duan68e597d2020-06-22 19:59:40 +080010#include <timer.h>
Huayang Duanc90a9e62020-06-22 19:52:45 +080011
Xi Chene8c681c2021-03-03 17:58:07 +080012const char *get_dram_geometry_str(u32 ddr_geometry);
13const char *get_dram_type_str(u32 ddr_type);
14
Huayang Duanc90a9e62020-06-22 19:52:45 +080015static int mt_mem_test(const struct dramc_data *dparam)
16{
17 if (CONFIG(MEMORY_TEST)) {
18 u8 *addr = _dram;
19 const struct ddr_base_info *ddr_info = &dparam->ddr_info;
20
21 for (u8 rank = RANK_0; rank < ddr_info->support_ranks; rank++) {
Xi Chen3827f562020-10-20 17:55:14 +080022 int result = complex_mem_test(addr, 0x2000);
Huayang Duanc90a9e62020-06-22 19:52:45 +080023
Xi Chen3827f562020-10-20 17:55:14 +080024 if (result != 0) {
25 printk(BIOS_ERR,
26 "[MEM] complex R/W mem test failed: %d\n", result);
Huayang Duanc90a9e62020-06-22 19:52:45 +080027 return -1;
Huayang Duanc90a9e62020-06-22 19:52:45 +080028 }
Xi Chene8c681c2021-03-03 17:58:07 +080029 printk(BIOS_DEBUG, "[MEM] rank %u complex R/W mem test passed\n", rank);
Huayang Duanc90a9e62020-06-22 19:52:45 +080030
31 addr += ddr_info->rank_size[rank];
32 }
33 }
34
35 return 0;
36}
37
38static u32 compute_checksum(const struct dramc_param *dparam)
39{
40 return (u32)compute_ip_checksum(&dparam->dramc_datas,
41 sizeof(dparam->dramc_datas));
42}
43
Xi Chene8c681c2021-03-03 17:58:07 +080044const char *get_dram_geometry_str(u32 ddr_geometry)
45{
46 const char *s;
47
48 switch (ddr_geometry) {
49 case DDR_TYPE_2CH_2RK_4GB_2_2:
50 s = "2CH_2RK_4GB_2_2";
51 break;
52 case DDR_TYPE_2CH_2RK_6GB_3_3:
53 s = "2CH_2RK_6GB_3_3";
54 break;
55 case DDR_TYPE_2CH_2RK_8GB_4_4:
56 s = "2CH_2RK_8GB_4_4";
57 break;
58 case DDR_TYPE_2CH_2RK_8GB_4_4_BYTE:
59 s = "2CH_2RK_8GB_4_4_BYTE";
60 break;
61 case DDR_TYPE_2CH_1RK_4GB_4_0:
62 s = "2CH_1RK_4GB_4_0";
63 break;
64 case DDR_TYPE_2CH_2RK_6GB_2_4:
65 s = "2CH_2RK_6GB_2_4";
66 break;
67 default:
68 s = "";
69 break;
70 }
71
72 return s;
73}
74
75const char *get_dram_type_str(u32 ddr_type)
76{
77 const char *s;
78
79 switch (ddr_type) {
80 case DDR_TYPE_DISCRETE:
81 s = "DSC";
82 break;
83 case DDR_TYPE_EMCP:
84 s = "EMCP";
85 break;
86 default:
87 s = "";
88 break;
89 }
90
91 return s;
92}
93
94static int dram_run_fast_calibration(struct dramc_param *dparam)
Huayang Duanc90a9e62020-06-22 19:52:45 +080095{
96 if (!is_valid_dramc_param(dparam)) {
Huayang Duan68e597d2020-06-22 19:59:40 +080097 printk(BIOS_WARNING, "DRAM-K: Invalid DRAM calibration data from flash\n");
Huayang Duanc90a9e62020-06-22 19:52:45 +080098 dump_param_header((void *)dparam);
99 return -1;
100 }
101
102 const u32 checksum = compute_checksum(dparam);
103 if (dparam->header.checksum != checksum) {
104 printk(BIOS_ERR,
Huayang Duan68e597d2020-06-22 19:59:40 +0800105 "DRAM-K: Invalid DRAM calibration checksum from flash "
Huayang Duanc90a9e62020-06-22 19:52:45 +0800106 "(expected: %#x, saved: %#x)\n",
107 checksum, dparam->header.checksum);
108 return DRAMC_ERR_INVALID_CHECKSUM;
109 }
110
Xi Chene8c681c2021-03-03 17:58:07 +0800111 const u16 config = CONFIG(MEDIATEK_DRAM_DVFS) ? DRAMC_ENABLE_DVFS : DRAMC_DISABLE_DVFS;
Huayang Duanc90a9e62020-06-22 19:52:45 +0800112 if (dparam->dramc_datas.ddr_info.config_dvfs != config) {
113 printk(BIOS_WARNING,
Huayang Duan68e597d2020-06-22 19:59:40 +0800114 "DRAM-K: Incompatible config for calibration data from flash "
Huayang Duanc90a9e62020-06-22 19:52:45 +0800115 "(expected: %#x, saved: %#x)\n",
116 config, dparam->dramc_datas.ddr_info.config_dvfs);
117 return -1;
118 }
119
Huayang Duan68e597d2020-06-22 19:59:40 +0800120 printk(BIOS_INFO, "DRAM-K: DRAM calibration data valid pass\n");
Xi Chene8c681c2021-03-03 17:58:07 +0800121 init_dram_by_params(dparam);
Huayang Duanc90a9e62020-06-22 19:52:45 +0800122 if (mt_mem_test(&dparam->dramc_datas) == 0)
123 return 0;
124
125 return DRAMC_ERR_FAST_CALIBRATION;
126}
127
Huayang Duan68e597d2020-06-22 19:59:40 +0800128static int dram_run_full_calibration(struct dramc_param *dparam)
129{
130 /* Load and run the provided blob for full-calibration if available */
131 struct prog dram = PROG_INIT(PROG_REFCODE, CONFIG_CBFS_PREFIX "/dram");
132
133 initialize_dramc_param(dparam);
134
135 if (prog_locate(&dram)) {
136 printk(BIOS_ERR, "DRAM-K: Locate program failed\n");
137 return -1;
138 }
139
140 if (cbfs_prog_stage_load(&dram)) {
141 printk(BIOS_ERR, "DRAM-K: CBFS load program failed\n");
142 return -2;
143 }
144
145 dparam->do_putc = do_putchar;
146
147 prog_set_entry(&dram, prog_entry(&dram), dparam);
148 prog_run(&dram);
149 if (dparam->header.status != DRAMC_SUCCESS) {
150 printk(BIOS_ERR, "DRAM-K: Full calibration failed: status = %d\n",
Xi Chene8c681c2021-03-03 17:58:07 +0800151 dparam->header.status);
Huayang Duan68e597d2020-06-22 19:59:40 +0800152 return -3;
153 }
154
155 if (!(dparam->header.flags & DRAMC_FLAG_HAS_SAVED_DATA)) {
156 printk(BIOS_ERR,
157 "DRAM-K: Full calibration executed without saving parameters. "
158 "Please ensure the blob is built properly.\n");
159 return -4;
160 }
161
162 return 0;
163}
164
Huayang Duanc90a9e62020-06-22 19:52:45 +0800165static void mem_init_set_default_config(struct dramc_param *dparam,
Xi Chene8c681c2021-03-03 17:58:07 +0800166 const struct sdram_info *dram_info)
Huayang Duanc90a9e62020-06-22 19:52:45 +0800167{
Xi Chene8c681c2021-03-03 17:58:07 +0800168 u32 type, geometry;
Huayang Duanc90a9e62020-06-22 19:52:45 +0800169 memset(dparam, 0, sizeof(*dparam));
170
Xi Chene8c681c2021-03-03 17:58:07 +0800171 type = dram_info->ddr_type;
172 geometry = dram_info->ddr_geometry;
Huayang Duanc90a9e62020-06-22 19:52:45 +0800173
Xi Chene8c681c2021-03-03 17:58:07 +0800174 dparam->dramc_datas.ddr_info.ddr_type = type;
175
176 if (CONFIG(MEDIATEK_DRAM_DVFS))
Huayang Duanc90a9e62020-06-22 19:52:45 +0800177 dparam->dramc_datas.ddr_info.config_dvfs = DRAMC_ENABLE_DVFS;
Huayang Duanc90a9e62020-06-22 19:52:45 +0800178
Xi Chene8c681c2021-03-03 17:58:07 +0800179 dparam->dramc_datas.ddr_info.ddr_geometry = geometry;
180
181 printk(BIOS_INFO, "DRAM-K: ddr_type: %s, config_dvfs: %d, ddr_geometry: %s\n",
182 get_dram_type_str(type),
183 dparam->dramc_datas.ddr_info.config_dvfs,
184 get_dram_geometry_str(geometry));
Huayang Duanc90a9e62020-06-22 19:52:45 +0800185}
186
Xi Chene8c681c2021-03-03 17:58:07 +0800187static void mt_mem_init_run(struct dramc_param_ops *dparam_ops,
188 const struct sdram_info *dram_info)
Huayang Duanc90a9e62020-06-22 19:52:45 +0800189{
190 struct dramc_param *dparam = dparam_ops->param;
Huayang Duan68e597d2020-06-22 19:59:40 +0800191 struct stopwatch sw;
192 int ret;
Huayang Duanc90a9e62020-06-22 19:52:45 +0800193
194 /* Load calibration params from flash and run fast calibration */
Xi Chene8c681c2021-03-03 17:58:07 +0800195 mem_init_set_default_config(dparam, dram_info);
Huayang Duanc90a9e62020-06-22 19:52:45 +0800196 if (dparam_ops->read_from_flash(dparam)) {
197 printk(BIOS_INFO, "DRAM-K: Running fast calibration\n");
Huayang Duan68e597d2020-06-22 19:59:40 +0800198 stopwatch_init(&sw);
199
200 ret = dram_run_fast_calibration(dparam);
201 if (ret != 0) {
202 printk(BIOS_ERR, "DRAM-K: Failed to run fast calibration "
203 "in %ld msecs, error: %d\n",
204 stopwatch_duration_msecs(&sw), ret);
Huayang Duanc90a9e62020-06-22 19:52:45 +0800205
206 /* Erase flash data after fast calibration failed */
207 memset(dparam, 0xa5, sizeof(*dparam));
208 dparam_ops->write_to_flash(dparam);
209 } else {
Huayang Duan68e597d2020-06-22 19:59:40 +0800210 printk(BIOS_INFO, "DRAM-K: Fast calibration passed in %ld msecs\n",
211 stopwatch_duration_msecs(&sw));
Huayang Duanc90a9e62020-06-22 19:52:45 +0800212 return;
213 }
214 } else {
Huayang Duan68e597d2020-06-22 19:59:40 +0800215 printk(BIOS_WARNING, "DRAM-K: Failed to read calibration data from flash\n");
216 }
217
218 /* Run full calibration */
219 printk(BIOS_INFO, "DRAM-K: Running full calibration\n");
Xi Chene8c681c2021-03-03 17:58:07 +0800220 mem_init_set_default_config(dparam, dram_info);
Huayang Duan68e597d2020-06-22 19:59:40 +0800221
222 stopwatch_init(&sw);
223 int err = dram_run_full_calibration(dparam);
224 if (err == 0) {
225 printk(BIOS_INFO, "DRAM-K: Full calibration passed in %ld msecs\n",
226 stopwatch_duration_msecs(&sw));
227
228 dparam->header.checksum = compute_checksum(dparam);
229 dparam_ops->write_to_flash(dparam);
230 printk(BIOS_DEBUG, "DRAM-K: Calibration params saved to flash: "
231 "version=%#x, size=%#x\n",
232 dparam->header.version, dparam->header.size);
233 } else {
234 printk(BIOS_ERR, "DRAM-K: Full calibration failed in %ld msecs\n",
235 stopwatch_duration_msecs(&sw));
Huayang Duanc90a9e62020-06-22 19:52:45 +0800236 }
237}
238
239void mt_mem_init(struct dramc_param_ops *dparam_ops)
240{
241 const struct sdram_info *sdram_param = get_sdram_config();
242
Xi Chene8c681c2021-03-03 17:58:07 +0800243 mt_mem_init_run(dparam_ops, sdram_param);
Huayang Duanc90a9e62020-06-22 19:52:45 +0800244}