blob: b8bda6e82cc37c6468421bab183461fe21f11514 [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
Huayang Duan68e597d2020-06-22 19:59:40 +0800135 if (cbfs_prog_stage_load(&dram)) {
136 printk(BIOS_ERR, "DRAM-K: CBFS load program failed\n");
137 return -2;
138 }
139
140 dparam->do_putc = do_putchar;
141
142 prog_set_entry(&dram, prog_entry(&dram), dparam);
143 prog_run(&dram);
144 if (dparam->header.status != DRAMC_SUCCESS) {
145 printk(BIOS_ERR, "DRAM-K: Full calibration failed: status = %d\n",
Xi Chene8c681c2021-03-03 17:58:07 +0800146 dparam->header.status);
Huayang Duan68e597d2020-06-22 19:59:40 +0800147 return -3;
148 }
149
150 if (!(dparam->header.flags & DRAMC_FLAG_HAS_SAVED_DATA)) {
151 printk(BIOS_ERR,
152 "DRAM-K: Full calibration executed without saving parameters. "
153 "Please ensure the blob is built properly.\n");
154 return -4;
155 }
156
157 return 0;
158}
159
Huayang Duanc90a9e62020-06-22 19:52:45 +0800160static void mem_init_set_default_config(struct dramc_param *dparam,
Xi Chene8c681c2021-03-03 17:58:07 +0800161 const struct sdram_info *dram_info)
Huayang Duanc90a9e62020-06-22 19:52:45 +0800162{
Xi Chene8c681c2021-03-03 17:58:07 +0800163 u32 type, geometry;
Huayang Duanc90a9e62020-06-22 19:52:45 +0800164 memset(dparam, 0, sizeof(*dparam));
165
Xi Chene8c681c2021-03-03 17:58:07 +0800166 type = dram_info->ddr_type;
167 geometry = dram_info->ddr_geometry;
Huayang Duanc90a9e62020-06-22 19:52:45 +0800168
Xi Chene8c681c2021-03-03 17:58:07 +0800169 dparam->dramc_datas.ddr_info.ddr_type = type;
170
171 if (CONFIG(MEDIATEK_DRAM_DVFS))
Huayang Duanc90a9e62020-06-22 19:52:45 +0800172 dparam->dramc_datas.ddr_info.config_dvfs = DRAMC_ENABLE_DVFS;
Huayang Duanc90a9e62020-06-22 19:52:45 +0800173
Xi Chene8c681c2021-03-03 17:58:07 +0800174 dparam->dramc_datas.ddr_info.ddr_geometry = geometry;
175
176 printk(BIOS_INFO, "DRAM-K: ddr_type: %s, config_dvfs: %d, ddr_geometry: %s\n",
177 get_dram_type_str(type),
178 dparam->dramc_datas.ddr_info.config_dvfs,
179 get_dram_geometry_str(geometry));
Huayang Duanc90a9e62020-06-22 19:52:45 +0800180}
181
Xi Chene8c681c2021-03-03 17:58:07 +0800182static void mt_mem_init_run(struct dramc_param_ops *dparam_ops,
183 const struct sdram_info *dram_info)
Huayang Duanc90a9e62020-06-22 19:52:45 +0800184{
185 struct dramc_param *dparam = dparam_ops->param;
Huayang Duan68e597d2020-06-22 19:59:40 +0800186 struct stopwatch sw;
187 int ret;
Huayang Duanc90a9e62020-06-22 19:52:45 +0800188
189 /* Load calibration params from flash and run fast calibration */
Xi Chene8c681c2021-03-03 17:58:07 +0800190 mem_init_set_default_config(dparam, dram_info);
Huayang Duanc90a9e62020-06-22 19:52:45 +0800191 if (dparam_ops->read_from_flash(dparam)) {
192 printk(BIOS_INFO, "DRAM-K: Running fast calibration\n");
Huayang Duan68e597d2020-06-22 19:59:40 +0800193 stopwatch_init(&sw);
194
195 ret = dram_run_fast_calibration(dparam);
196 if (ret != 0) {
197 printk(BIOS_ERR, "DRAM-K: Failed to run fast calibration "
198 "in %ld msecs, error: %d\n",
199 stopwatch_duration_msecs(&sw), ret);
Huayang Duanc90a9e62020-06-22 19:52:45 +0800200
201 /* Erase flash data after fast calibration failed */
202 memset(dparam, 0xa5, sizeof(*dparam));
203 dparam_ops->write_to_flash(dparam);
204 } else {
Huayang Duan68e597d2020-06-22 19:59:40 +0800205 printk(BIOS_INFO, "DRAM-K: Fast calibration passed in %ld msecs\n",
206 stopwatch_duration_msecs(&sw));
Huayang Duanc90a9e62020-06-22 19:52:45 +0800207 return;
208 }
209 } else {
Huayang Duan68e597d2020-06-22 19:59:40 +0800210 printk(BIOS_WARNING, "DRAM-K: Failed to read calibration data from flash\n");
211 }
212
213 /* Run full calibration */
214 printk(BIOS_INFO, "DRAM-K: Running full calibration\n");
Xi Chene8c681c2021-03-03 17:58:07 +0800215 mem_init_set_default_config(dparam, dram_info);
Huayang Duan68e597d2020-06-22 19:59:40 +0800216
217 stopwatch_init(&sw);
218 int err = dram_run_full_calibration(dparam);
219 if (err == 0) {
220 printk(BIOS_INFO, "DRAM-K: Full calibration passed in %ld msecs\n",
221 stopwatch_duration_msecs(&sw));
222
223 dparam->header.checksum = compute_checksum(dparam);
224 dparam_ops->write_to_flash(dparam);
225 printk(BIOS_DEBUG, "DRAM-K: Calibration params saved to flash: "
226 "version=%#x, size=%#x\n",
227 dparam->header.version, dparam->header.size);
228 } else {
229 printk(BIOS_ERR, "DRAM-K: Full calibration failed in %ld msecs\n",
230 stopwatch_duration_msecs(&sw));
Huayang Duanc90a9e62020-06-22 19:52:45 +0800231 }
232}
233
234void mt_mem_init(struct dramc_param_ops *dparam_ops)
235{
236 const struct sdram_info *sdram_param = get_sdram_config();
237
Xi Chene8c681c2021-03-03 17:58:07 +0800238 mt_mem_init_run(dparam_ops, sdram_param);
Huayang Duanc90a9e62020-06-22 19:52:45 +0800239}