coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
meminit.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include <assert.h>
4 #include <console/console.h>
5 #include <fsp/util.h>
6 #include <soc/meminit.h>
7 #include <string.h>
8 
9 #define LP4X_CH_WIDTH 16
10 #define LP4X_CHANNELS CHANNEL_COUNT(LP4X_CH_WIDTH)
11 
12 #define DDR4_CH_WIDTH 64
13 #define DDR4_CHANNELS CHANNEL_COUNT(DDR4_CH_WIDTH)
14 
15 static const struct soc_mem_cfg soc_mem_cfg[] = {
16  [MEM_TYPE_DDR4] = {
18  .phys_to_mrc_map = {
19  [0] = 0,
20  [1] = 4,
21  },
22  .md_phy_masks = {
23  /*
24  * Only physical channel 0 is populated in case of half-populated
25  * configuration.
26  */
27  .half_channel = BIT(0),
28  /* In mixed topologies, channel 0 is always memory-down. */
29  .mixed_topo = BIT(0),
30  },
31  },
32  [MEM_TYPE_LP4X] = {
33  .num_phys_channels = LP4X_CHANNELS,
34  .phys_to_mrc_map = {
35  [0] = 0,
36  [1] = 1,
37  [2] = 2,
38  [3] = 3,
39  [4] = 4,
40  [5] = 5,
41  [6] = 6,
42  [7] = 7,
43  },
44  .md_phy_masks = {
45  /*
46  * Physical channels 0, 1, 2 and 3 are populated in case of
47  * half-populated configurations.
48  */
49  .half_channel = BIT(0) | BIT(1) | BIT(2) | BIT(3),
50  /* LP4x does not support mixed topologies. */
51  },
52  },
53 };
54 
55 static void mem_init_spd_upds(FSP_M_CONFIG *mem_cfg, const struct mem_channel_data *data)
56 {
57  uint32_t *spd_upds[MRC_CHANNELS][CONFIG_DIMMS_PER_CHANNEL] = {
58  [0] = { &mem_cfg->MemorySpdPtr000, &mem_cfg->MemorySpdPtr001, },
59  [1] = { &mem_cfg->MemorySpdPtr010, &mem_cfg->MemorySpdPtr011, },
60  [2] = { &mem_cfg->MemorySpdPtr020, &mem_cfg->MemorySpdPtr021, },
61  [3] = { &mem_cfg->MemorySpdPtr030, &mem_cfg->MemorySpdPtr031, },
62  [4] = { &mem_cfg->MemorySpdPtr100, &mem_cfg->MemorySpdPtr101, },
63  [5] = { &mem_cfg->MemorySpdPtr110, &mem_cfg->MemorySpdPtr111, },
64  [6] = { &mem_cfg->MemorySpdPtr120, &mem_cfg->MemorySpdPtr121, },
65  [7] = { &mem_cfg->MemorySpdPtr130, &mem_cfg->MemorySpdPtr131, },
66  };
67  uint8_t *disable_dimm_upds[MRC_CHANNELS] = {
68  &mem_cfg->DisableDimmMc0Ch0,
69  &mem_cfg->DisableDimmMc0Ch1,
70  &mem_cfg->DisableDimmMc0Ch2,
71  &mem_cfg->DisableDimmMc0Ch3,
72  &mem_cfg->DisableDimmMc1Ch0,
73  &mem_cfg->DisableDimmMc1Ch1,
74  &mem_cfg->DisableDimmMc1Ch2,
75  &mem_cfg->DisableDimmMc1Ch3,
76  };
77  int ch, dimm;
78 
79  mem_cfg->MemorySpdDataLen = data->spd_len;
80 
81  for (ch = 0; ch < MRC_CHANNELS; ch++) {
82  uint8_t *disable_dimm_ptr = disable_dimm_upds[ch];
83  *disable_dimm_ptr = 0;
84 
85  for (dimm = 0; dimm < CONFIG_DIMMS_PER_CHANNEL; dimm++) {
86  uint32_t *spd_ptr = spd_upds[ch][dimm];
87 
88  *spd_ptr = data->spd[ch][dimm];
89  if (!*spd_ptr)
90  *disable_dimm_ptr |= BIT(dimm);
91  }
92  }
93 }
94 
95 static void mem_init_dq_dqs_upds(void *upds[MRC_CHANNELS], const void *map, size_t upd_size,
96  const struct mem_channel_data *data)
97 {
98  size_t i;
99 
100  for (i = 0; i < MRC_CHANNELS; i++, map += upd_size) {
102  memcpy(upds[i], map, upd_size);
103  else
104  memset(upds[i], 0, upd_size);
105  }
106 }
107 
108 static void mem_init_dq_upds(FSP_M_CONFIG *mem_cfg, const struct mem_channel_data *data,
109  const struct mb_cfg *mb_cfg)
110 {
111  void *dq_upds[MRC_CHANNELS] = {
112  &mem_cfg->DqMapCpu2DramMc0Ch0,
113  &mem_cfg->DqMapCpu2DramMc0Ch1,
114  &mem_cfg->DqMapCpu2DramMc0Ch2,
115  &mem_cfg->DqMapCpu2DramMc0Ch3,
116  &mem_cfg->DqMapCpu2DramMc1Ch0,
117  &mem_cfg->DqMapCpu2DramMc1Ch1,
118  &mem_cfg->DqMapCpu2DramMc1Ch2,
119  &mem_cfg->DqMapCpu2DramMc1Ch3,
120  };
121 
122  const size_t upd_size = sizeof(mem_cfg->DqMapCpu2DramMc0Ch0);
123 
124  _Static_assert(upd_size == CONFIG_MRC_CHANNEL_WIDTH, "Incorrect DQ UPD size!");
125 
126  mem_init_dq_dqs_upds(dq_upds, mb_cfg->dq_map, upd_size, data);
127 }
128 
129 static void mem_init_dqs_upds(FSP_M_CONFIG *mem_cfg, const struct mem_channel_data *data,
130  const struct mb_cfg *mb_cfg)
131 {
132  void *dqs_upds[MRC_CHANNELS] = {
133  &mem_cfg->DqsMapCpu2DramMc0Ch0,
134  &mem_cfg->DqsMapCpu2DramMc0Ch1,
135  &mem_cfg->DqsMapCpu2DramMc0Ch2,
136  &mem_cfg->DqsMapCpu2DramMc0Ch3,
137  &mem_cfg->DqsMapCpu2DramMc1Ch0,
138  &mem_cfg->DqsMapCpu2DramMc1Ch1,
139  &mem_cfg->DqsMapCpu2DramMc1Ch2,
140  &mem_cfg->DqsMapCpu2DramMc1Ch3,
141  };
142 
143  const size_t upd_size = sizeof(mem_cfg->DqsMapCpu2DramMc0Ch0);
144 
145  _Static_assert(upd_size == CONFIG_MRC_CHANNEL_WIDTH / 8, "Incorrect DQS UPD size!");
146 
147  mem_init_dq_dqs_upds(dqs_upds, mb_cfg->dqs_map, upd_size, data);
148 }
149 
150 void memcfg_init(FSPM_UPD *memupd, const struct mb_cfg *mb_cfg,
151  const struct mem_spd *spd_info, bool half_populated)
152 {
153  struct mem_channel_data data;
154  FSP_M_CONFIG *mem_cfg = &memupd->FspmConfig;
155 
157  die("Invalid memory type(%x)!\n", mb_cfg->type);
158 
159  mem_populate_channel_data(memupd, &soc_mem_cfg[mb_cfg->type], spd_info, half_populated,
160  &data);
161  mem_init_spd_upds(mem_cfg, &data);
162  mem_init_dq_upds(mem_cfg, &data, mb_cfg);
163  mem_init_dqs_upds(mem_cfg, &data, mb_cfg);
164 
165  mem_cfg->ECT = mb_cfg->ect;
166 
167  switch (mb_cfg->type) {
168  case MEM_TYPE_DDR4:
169  mem_cfg->DqPinsInterleaved = mb_cfg->ddr4_config.dq_pins_interleaved;
170  break;
171  case MEM_TYPE_LP4X:
172  /* LPDDR4x does not allow interleaved memory */
173  mem_cfg->DqPinsInterleaved = 0;
174  break;
175  default:
176  die("Unsupported memory type(%d)\n", mb_cfg->type);
177  }
178 
179 }
@ MEM_TYPE_LP4X
Definition: meminit.h:13
@ MEM_TYPE_DDR4
Definition: meminit.h:11
void memcfg_init(FSPM_UPD *memupd, const struct mb_cfg *mb_cfg, const struct mem_spd *spd_info, bool half_populated)
Definition: meminit.c:238
void * memcpy(void *dest, const void *src, size_t n)
Definition: memcpy.c:7
void * memset(void *dstpp, int c, size_t len)
Definition: memset.c:12
#define ARRAY_SIZE(a)
Definition: helpers.h:12
static bool channel_is_populated(size_t curr_ch, size_t max_ch, enum channel_population flags)
Definition: meminit.h:150
#define MRC_CHANNELS
Definition: meminit.h:21
void mem_populate_channel_data(FSPM_UPD *memupd, const struct soc_mem_cfg *soc_mem_cfg, const struct mem_spd *spd_info, bool half_populated, struct mem_channel_data *data)
Definition: meminit.c:187
_Static_assert(CONFIG_MRC_CHANNEL_WIDTH > 0, "MRC channel width must be >0!")
void __noreturn die(const char *fmt,...)
Definition: die.c:17
#define BIT(nr)
Definition: ec_commands.h:45
#define FSP_M_CONFIG
Definition: fsp_upd.h:8
static struct dramc_channel const ch[2]
unsigned int uint32_t
Definition: stdint.h:14
unsigned char uint8_t
Definition: stdint.h:8
Definition: meminit.h:71
bool ect
Definition: meminit.h:100
uint8_t dqs_map[CONFIG_DATA_BUS_WIDTH/BITS_PER_BYTE]
Definition: meminit.h:90
enum mem_type type
Definition: meminit.h:72
struct mem_ddr4_config ddr4_config
Definition: meminit.h:111
uint8_t dq_map[CONFIG_DATA_BUS_WIDTH]
Definition: meminit.h:80
uintptr_t spd[MRC_CHANNELS][CONFIG_DIMMS_PER_CHANNEL]
Definition: meminit.h:124
enum channel_population ch_population_flags
Definition: meminit.h:128
size_t spd_len
Definition: meminit.h:126
bool dq_pins_interleaved
Definition: meminit.h:80
size_t num_phys_channels
Definition: meminit.h:68
Definition: spd.h:11
static void mem_init_spd_upds(FSP_M_CONFIG *mem_cfg, const struct mem_channel_data *data)
Definition: meminit.c:55
#define DDR4_CHANNELS
Definition: meminit.c:13
static void mem_init_dqs_upds(FSP_M_CONFIG *mem_cfg, const struct mem_channel_data *data, const struct mb_cfg *mb_cfg)
Definition: meminit.c:129
static void mem_init_dq_upds(FSP_M_CONFIG *mem_cfg, const struct mem_channel_data *data, const struct mb_cfg *mb_cfg)
Definition: meminit.c:108
#define LP4X_CHANNELS
Definition: meminit.c:10
static void mem_init_dq_dqs_upds(void *upds[MRC_CHANNELS], const void *map, size_t upd_size, const struct mem_channel_data *data)
Definition: meminit.c:95