coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
memory.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <assert.h>
4 #include <cbfs.h>
5 #include <cbmem.h>
7 #include <console/console.h>
8 #include <soc/dramc_common.h>
9 #include <ip_checksum.h>
10 #include <mrc_cache.h>
11 #include <soc/dramc_param.h>
12 #include <soc/emi.h>
13 #include <soc/mmu_operations.h>
14 #include <symbols.h>
15 #include <timer.h>
16 
17 /* This must be defined in chromeos.fmd in same name and size. */
18 #define CALIBRATION_REGION "RW_MRC_CACHE"
19 #define CALIBRATION_REGION_SIZE 0x2000
20 
22  "sizeof(struct dramc_param) exceeds " CALIBRATION_REGION);
23 
24 const char *get_dram_geometry_str(u32 ddr_geometry);
25 const char *get_dram_type_str(u32 ddr_type);
26 
27 static const struct ddr_base_info *curr_ddr_info;
28 
29 static int mt_mem_test(const struct dramc_data *dparam)
30 {
31  if (CONFIG(MEMORY_TEST)) {
32  u8 *addr = _dram;
33  const struct ddr_base_info *ddr_info = &dparam->ddr_info;
34 
35  for (u8 rank = RANK_0; rank < ddr_info->support_ranks; rank++) {
36  int result = complex_mem_test(addr, 0x2000);
37 
38  if (result != 0) {
40  "[MEM] complex R/W mem test failed: %d\n", result);
41  return -1;
42  }
43  printk(BIOS_DEBUG, "[MEM] rank %u complex R/W mem test passed\n", rank);
44 
45  addr += ddr_info->rank_size[rank];
46  }
47  }
48 
49  return 0;
50 }
51 
52 const char *get_dram_geometry_str(u32 ddr_geometry)
53 {
54  const char *s;
55 
56  switch (ddr_geometry) {
58  s = "2CH_2RK_4GB_2_2";
59  break;
61  s = "2CH_2RK_6GB_3_3";
62  break;
64  s = "2CH_2RK_8GB_4_4";
65  break;
67  s = "2CH_2RK_8GB_4_4_BYTE";
68  break;
70  s = "2CH_1RK_4GB_4_0";
71  break;
73  s = "2CH_2RK_6GB_2_4";
74  break;
75  default:
76  s = "";
77  break;
78  }
79 
80  return s;
81 }
82 
83 const char *get_dram_type_str(u32 ddr_type)
84 {
85  const char *s;
86 
87  switch (ddr_type) {
88  case DDR_TYPE_DISCRETE:
89  s = "DSC";
90  break;
91  case DDR_TYPE_EMCP:
92  s = "EMCP";
93  break;
94  default:
95  s = "";
96  break;
97  }
98 
99  return s;
100 }
101 
102 size_t mtk_dram_size(void)
103 {
104  size_t size = 0;
105 
106  if (!curr_ddr_info)
107  return 0;
108  for (unsigned int i = 0; i < RANK_MAX; ++i)
109  size += curr_ddr_info->mrr_info.mr8_density[i];
110  return size;
111 }
112 
113 static void fill_dram_info(struct mem_chip_info *mc, const struct ddr_base_info *ddr)
114 {
115  unsigned int i;
116  size_t size;
117 
118  mc->type = MEM_CHIP_LPDDR4X;
120  size = mtk_dram_size();
121  assert(size);
122 
123  for (i = 0; i < mc->num_channels; ++i) {
124  mc->channel[i].density = size / mc->num_channels;
126  mc->channel[i].manufacturer_id = ddr->mrr_info.mr5_vendor_id;
127  mc->channel[i].revision_id[0] = ddr->mrr_info.mr6_revision_id;
128  mc->channel[i].revision_id[1] = ddr->mrr_info.mr7_revision_id;
129  }
130 }
131 
132 static void add_mem_chip_info(int unused)
133 {
134  struct mem_chip_info *mc;
135  size_t size;
136 
137  if (!CONFIG(USE_CBMEM_DRAM_INFO)) {
139  "DRAM-K: CBMEM DRAM info is unsupported (USE_CBMEM_DRAM_INFO)\n");
140  return;
141  }
142 
143  size = sizeof(*mc) + sizeof(struct mem_chip_channel) * CHANNEL_MAX;
144  mc = cbmem_add(CBMEM_ID_MEM_CHIP_INFO, size);
145  assert(mc);
146 
148 }
150 
151 static int run_dram_blob(struct dramc_param *dparam)
152 {
153  /* Load and run the provided blob for full-calibration if available */
154  struct prog dram = PROG_INIT(PROG_REFCODE, CONFIG_CBFS_PREFIX "/dram");
155 
156  dump_param_header(dparam);
157 
158  if (cbfs_prog_stage_load(&dram)) {
159  printk(BIOS_ERR, "DRAM-K: CBFS load program failed\n");
160  return -2;
161  }
162 
163  dparam->do_putc = do_putchar;
164 
165  prog_set_entry(&dram, prog_entry(&dram), dparam);
166  prog_run(&dram);
167  if (dparam->header.status != DRAMC_SUCCESS) {
168  printk(BIOS_ERR, "DRAM-K: calibration failed: status = %d\n",
169  dparam->header.status);
170  return -3;
171  }
172 
173  if (!(dparam->header.config & DRAMC_CONFIG_FAST_K)
174  && !(dparam->header.flags & DRAMC_FLAG_HAS_SAVED_DATA)) {
176  "DRAM-K: Full calibration executed without saving parameters. "
177  "Please ensure the blob is built properly.\n");
178  return -4;
179  }
180 
181  return 0;
182 }
183 
184 static int dram_run_fast_calibration(struct dramc_param *dparam)
185 {
186  const u16 config = CONFIG(MEDIATEK_DRAM_DVFS) ? DRAMC_ENABLE_DVFS : DRAMC_DISABLE_DVFS;
187 
188  if (dparam->dramc_datas.ddr_info.config_dvfs != config) {
190  "DRAM-K: Incompatible config for calibration data from flash "
191  "(expected: %#x, saved: %#x)\n",
193  return -1;
194  }
195 
196  printk(BIOS_INFO, "DRAM-K: DRAM calibration data valid pass\n");
197 
198  if (CONFIG(MEDIATEK_BLOB_FAST_INIT)) {
199  printk(BIOS_INFO, "DRAM-K: Run fast calibration run in blob mode\n");
200 
201  /*
202  * The loaded config should not contain FAST_K (done in full calibration),
203  * so we have to set that now to indicate the blob taking the config instead
204  * of generating a new config.
205  */
206  dparam->header.config |= DRAMC_CONFIG_FAST_K;
207 
208  if (run_dram_blob(dparam) < 0)
209  return -3;
210  } else {
211  init_dram_by_params(dparam);
212  }
213 
214  if (mt_mem_test(&dparam->dramc_datas) < 0)
215  return -4;
216 
217  return 0;
218 }
219 
220 static int dram_run_full_calibration(struct dramc_param *dparam)
221 {
222  initialize_dramc_param(dparam);
223 
224  return run_dram_blob(dparam);
225 }
226 
227 static void mem_init_set_default_config(struct dramc_param *dparam,
228  const struct sdram_info *dram_info)
229 {
230  u32 type, geometry;
231  memset(dparam, 0, sizeof(*dparam));
232 
233  type = dram_info->ddr_type;
234  geometry = dram_info->ddr_geometry;
235 
237 
238  if (CONFIG(MEDIATEK_DRAM_DVFS))
240 
241  dparam->dramc_datas.ddr_info.sdram.ddr_geometry = geometry;
242 
243  printk(BIOS_INFO, "DRAM-K: ddr_type: %s, config_dvfs: %d, ddr_geometry: %s\n",
246  get_dram_geometry_str(geometry));
247 }
248 
249 static void mt_mem_init_run(struct dramc_param *dparam,
250  const struct sdram_info *dram_info)
251 {
252  const ssize_t mrc_cache_size = sizeof(*dparam);
253  ssize_t data_size;
254  struct stopwatch sw;
255  int ret;
256 
257  /* Load calibration params from flash and run fast calibration */
260  dparam, mrc_cache_size);
261  if (data_size == mrc_cache_size) {
262  printk(BIOS_INFO, "DRAM-K: Running fast calibration\n");
263  stopwatch_init(&sw);
264 
265  ret = dram_run_fast_calibration(dparam);
266  if (ret != 0) {
267  printk(BIOS_ERR, "DRAM-K: Failed to run fast calibration "
268  "in %ld msecs, error: %d\n",
269  stopwatch_duration_msecs(&sw), ret);
270 
271  /* Erase flash data after fast calibration failed */
272  memset(dparam, 0xa5, mrc_cache_size);
275  dparam, mrc_cache_size);
276  } else {
277  printk(BIOS_INFO, "DRAM-K: Fast calibration passed in %ld msecs\n",
279  return;
280  }
281  } else {
282  printk(BIOS_WARNING, "DRAM-K: Invalid data in flash (size: %#zx, expected: %#zx)\n",
283  data_size, mrc_cache_size);
284  }
285 
286  /* Run full calibration */
287  printk(BIOS_INFO, "DRAM-K: Running full calibration\n");
289 
290  stopwatch_init(&sw);
291  int err = dram_run_full_calibration(dparam);
292  if (err == 0) {
293  printk(BIOS_INFO, "DRAM-K: Full calibration passed in %ld msecs\n",
297  dparam, mrc_cache_size);
298  } else {
299  printk(BIOS_ERR, "DRAM-K: Full calibration failed in %ld msecs\n",
301  }
302 }
303 
304 void mt_mem_init(struct dramc_param *dparam)
305 {
306  const struct sdram_info *sdram_param = get_sdram_config();
307 
308  mt_mem_init_run(dparam, sdram_param);
309 }
310 
311 void mtk_dram_init(void)
312 {
313  /* dramc_param is too large to fit in stack. */
314  static struct dramc_param dramc_parameter;
318 }
void * memset(void *dstpp, int c, size_t len)
Definition: memset.c:12
#define assert(statement)
Definition: assert.h:74
const struct sdram_info * get_sdram_config(void)
Definition: sdram_configs.c:85
enum cb_err cbfs_prog_stage_load(struct prog *prog)
Definition: cbfs.c:523
void * cbmem_add(u32 id, u64 size)
Definition: imd_cbmem.c:144
#define CBMEM_ID_MEM_CHIP_INFO
Definition: cbmem_id.h:82
static u32 addr
Definition: cirrus.c:14
int initialize_dramc_param(void *blob)
Definition: dramc_param.c:27
int complex_mem_test(u8 *start, unsigned int len)
Definition: memory_test.c:25
#define printk(level,...)
Definition: stdlib.h:16
void do_putchar(unsigned char byte)
Definition: printk.c:55
void init_dram_by_params(struct dramc_param *dparam)
Definition: dram_init.c:31
@ RANK_0
@ RANK_MAX
@ CHANNEL_MAX
@ DRAMC_DISABLE_DVFS
@ DRAMC_ENABLE_DVFS
@ DDR_TYPE_2CH_2RK_8GB_4_4
@ DDR_TYPE_2CH_2RK_8GB_4_4_BYTE
@ DDR_TYPE_2CH_2RK_4GB_2_2
@ DDR_TYPE_2CH_2RK_6GB_3_3
@ DDR_TYPE_2CH_1RK_4GB_4_0
@ DDR_TYPE_2CH_2RK_6GB_2_4
@ DRAMC_SUCCESS
@ DRAMC_CONFIG_FAST_K
@ DRAMC_FLAG_HAS_SAVED_DATA
@ DDR_TYPE_EMCP
@ DDR_TYPE_DISCRETE
@ CONFIG
Definition: dsi_common.h:201
u8 _dram[]
static void stopwatch_init(struct stopwatch *sw)
Definition: timer.h:117
static long stopwatch_duration_msecs(struct stopwatch *sw)
Definition: timer.h:182
unsigned int type
Definition: edid.c:57
#define BIOS_INFO
BIOS_INFO - Expected events.
Definition: loglevel.h:113
#define BIOS_DEBUG
BIOS_DEBUG - Verbose output.
Definition: loglevel.h:128
#define BIOS_ERR
BIOS_ERR - System in incomplete state.
Definition: loglevel.h:72
#define BIOS_WARNING
BIOS_WARNING - Bad configuration.
Definition: loglevel.h:86
enum board_config config
Definition: memory.c:448
static struct dramc_param dramc_parameter
Definition: romstage.c:43
void mtk_mmu_after_dram(void)
@ MEM_CHIP_LPDDR4X
Definition: mem_chip_info.h:13
ssize_t mrc_cache_load_current(int type, uint32_t version, void *buffer, size_t buffer_size)
mrc_cache_load_current
Definition: mrc_cache.c:319
int mrc_cache_stash_data(int type, uint32_t version, const void *data, size_t size)
Returns < 0 on error, 0 on success.
Definition: mrc_cache.c:687
result
Definition: mrc_cache.c:35
@ MRC_TRAINING_DATA
Definition: mrc_cache.h:11
@ DRAMC_PARAM_HEADER_VERSION
Definition: dramc_param.h:13
#define DQ_DATA_WIDTH_LP4
Definition: dramc_soc.h:54
ddr
Definition: raminit.h:22
static void * prog_entry(const struct prog *prog)
#define PROG_INIT(type_, name_)
static void prog_set_entry(struct prog *prog, void *e, void *arg)
void prog_run(struct prog *prog)
Definition: prog_ops.c:24
@ PROG_REFCODE
static int run_dram_blob(struct dramc_param *dparam)
Definition: memory.c:151
_Static_assert(sizeof(struct dramc_param)<=CALIBRATION_REGION_SIZE, "sizeof(struct dramc_param) exceeds " CALIBRATION_REGION)
void mtk_dram_init(void)
Definition: memory.c:311
void mt_mem_init(struct dramc_param *dparam)
Definition: memory.c:304
#define CALIBRATION_REGION
Definition: memory.c:18
size_t mtk_dram_size(void)
Definition: memory.c:102
#define CALIBRATION_REGION_SIZE
Definition: memory.c:19
static int dram_run_full_calibration(struct dramc_param *dparam)
Definition: memory.c:220
ROMSTAGE_CBMEM_INIT_HOOK(add_mem_chip_info)
static void mt_mem_init_run(struct dramc_param *dparam, const struct sdram_info *dram_info)
Definition: memory.c:249
const char * get_dram_geometry_str(u32 ddr_geometry)
Definition: memory.c:52
static void add_mem_chip_info(int unused)
Definition: memory.c:132
const char * get_dram_type_str(u32 ddr_type)
Definition: memory.c:83
static void mem_init_set_default_config(struct dramc_param *dparam, const struct sdram_info *dram_info)
Definition: memory.c:227
static const struct ddr_base_info * curr_ddr_info
Definition: memory.c:27
static int mt_mem_test(const struct dramc_data *dparam)
Definition: memory.c:29
static void fill_dram_info(struct mem_chip_info *mc, const struct ddr_base_info *ddr)
Definition: memory.c:113
static int dram_run_fast_calibration(struct dramc_param *dparam)
Definition: memory.c:184
static void dump_param_header(const struct dramc_param *dparam)
Definition: memory.c:48
__SIZE_TYPE__ ssize_t
Definition: stddef.h:13
uint32_t u32
Definition: stdint.h:51
uint16_t u16
Definition: stdint.h:48
uint8_t u8
Definition: stdint.h:45
u64 rank_size[RANK_MAX]
struct sdram_info sdram
struct ddr_mrr_info mrr_info
u64 mr8_density[RANK_MAX]
struct ddr_base_info ddr_info
Definition: dramc_param.h:71
struct dramc_param_header header
Definition: dramc_param.h:61
struct dramc_data dramc_datas
Definition: dramc_param.h:78
void(* do_putc)(unsigned char c)
Definition: dramc_param.h:62
uint8_t num_channels
Definition: mem_chip_info.h:18
struct mem_chip_info::mem_chip_channel channel[0]
#define s(param, src_bits, pmcreg, dst_bits)