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-only */
2 #include <console/console.h>
3 #include <fsp/util.h>
4 #include <memory_info.h>
5 #include <soc/meminit.h>
6 #include <stddef.h> /* required for FspmUpd.h */
7 #include <fsp/soc_binding.h>
8 #include <string.h>
9 
10 static size_t memory_size_mib;
11 
13 {
14  return memory_size_mib;
15 }
16 
17 static void accumulate_channel_memory(int density, int dual_rank)
18 {
19  /* For this platform LPDDR4 memory is 4 DRAM parts that are x32. 2 of
20  the parts are composed into a x64 memory channel. Thus there are 2
21  channels composed of 2 DRAMs. */
22  size_t sz = density;
23 
24  /* Two DRAMs per channel. */
25  sz *= 2;
26 
27  /* Two ranks per channel. */
28  if (dual_rank)
29  sz *= 2;
30 
31  sz *= GiB / MiB;
32 
33  memory_size_mib += sz;
34 }
35 
36 size_t iohole_in_mib(void)
37 {
38  return 2 * (GiB / MiB);
39 }
40 
42 {
43  uint8_t odt_config;
44 
45  /* Enable memory down BGA since it's the only LPDDR4 packaging. */
46  cfg->Package = 1;
47  cfg->MemoryDown = 1;
48 
49  cfg->ScramblerSupport = 1;
50  cfg->ChannelHashMask = 0x36;
51  cfg->SliceHashMask = 0x9;
52  cfg->InterleavedMode = 2;
53  cfg->ChannelsSlicesEnable = 0;
54  cfg->MinRefRate2xEnable = 0;
55  cfg->DualRankSupportEnable = 1;
56  /* Don't enforce a memory size limit. */
57  cfg->MemorySizeLimit = 0;
58  /* Field is in MiB units. */
59  cfg->LowMemoryMaxValue = iohole_in_mib();
60  /* No restrictions on memory above 4GiB */
61  cfg->HighMemoryMaxValue = 0;
62 
63  /* Always default to attempt to use saved training data. */
64  cfg->DisableFastBoot = 0;
65 
66  /* LPDDR4 is memory down so no SPD addresses. */
67  cfg->DIMM0SPDAddress = 0;
68  cfg->DIMM1SPDAddress = 0;
69 
70  /* Clear all the rank enables. */
71  cfg->Ch0_RankEnable = 0x0;
72  cfg->Ch1_RankEnable = 0x0;
73  cfg->Ch2_RankEnable = 0x0;
74  cfg->Ch3_RankEnable = 0x0;
75 
76  /*
77  * Set the device width to x16 which is half a LPDDR4 module as that's
78  * what the reference code expects.
79  */
80  cfg->Ch0_DeviceWidth = 0x1;
81  cfg->Ch1_DeviceWidth = 0x1;
82  cfg->Ch2_DeviceWidth = 0x1;
83  cfg->Ch3_DeviceWidth = 0x1;
84 
85  /*
86  * Enable bank hashing (bit 1) and rank interleaving (bit 0) with
87  * a 1KiB address mapping (bits 5:4).
88  */
89  cfg->Ch0_Option = 0x3;
90  cfg->Ch1_Option = 0x3;
91  cfg->Ch2_Option = 0x3;
92  cfg->Ch3_Option = 0x3;
93 
94  /* Set CA ODT with default setting of ODT pins of LPDDR4 modules pulled
95  up to 1.1V. */
96  odt_config = ODT_A_B_HIGH_HIGH;
97 
98  cfg->Ch0_OdtConfig = odt_config;
99  cfg->Ch1_OdtConfig = odt_config;
100  cfg->Ch2_OdtConfig = odt_config;
101  cfg->Ch3_OdtConfig = odt_config;
102 }
103 
105  int logical;
107 };
108 
110  const struct speed_mapping *mappings;
111  size_t num_mappings;
112 };
113 
114 static const struct speed_mapping apl_mappings[] = {
115  { .logical = LP4_SPEED_1600, .fsp_value = 0x9 },
116  { .logical = LP4_SPEED_2133, .fsp_value = 0xa },
117  { .logical = LP4_SPEED_2400, .fsp_value = 0xb },
118 };
119 
120 static const struct fsp_speed_profiles apl_profile = {
122  .num_mappings = ARRAY_SIZE(apl_mappings),
123 };
124 
125 static const struct speed_mapping glk_mappings[] = {
126  { .logical = LP4_SPEED_1600, .fsp_value = 0x4 },
127  { .logical = LP4_SPEED_2133, .fsp_value = 0x6 },
128  { .logical = LP4_SPEED_2400, .fsp_value = 0x7 },
129 };
130 
131 static const struct fsp_speed_profiles glk_profile = {
133  .num_mappings = ARRAY_SIZE(glk_mappings),
134 };
135 
136 static const struct fsp_speed_profiles *get_fsp_profile(void)
137 {
138  if (CONFIG(SOC_INTEL_GEMINILAKE))
139  return &glk_profile;
140  else
141  return &apl_profile;
142 }
143 
144 static int validate_speed(int speed)
145 {
146  const struct fsp_speed_profiles *fsp_profile = get_fsp_profile();
147  size_t i;
148 
149  for (i = 0; i < fsp_profile->num_mappings; i++) {
150  /* Mapping exists. */
151  if (fsp_profile->mappings[i].logical == speed)
152  return speed;
153  }
154 
155  printk(BIOS_WARNING, "Invalid LPDDR4 speed: %d\n", speed);
156  /* Default to slowest speed */
157  return LP4_SPEED_1600;
158 }
159 
160 static int fsp_memory_profile(int speed)
161 {
162  const struct fsp_speed_profiles *fsp_profile = get_fsp_profile();
163  size_t i;
164 
165  for (i = 0; i < fsp_profile->num_mappings; i++) {
166  if (fsp_profile->mappings[i].logical == speed)
167  return fsp_profile->mappings[i].fsp_value;
168  }
169 
170  /* should never happen. */
171  return -1;
172 }
173 
174 void meminit_lpddr4(FSP_M_CONFIG *cfg, int speed)
175 {
176  speed = validate_speed(speed);
177 
178  printk(BIOS_INFO, "LP4DDR speed is %dMHz\n", speed);
179  cfg->Profile = fsp_memory_profile(speed);
180 
181  set_lpddr4_defaults(cfg);
182 }
183 
185  int rank_density, int dual_rank,
186  const struct lpddr4_swizzle_cfg *scfg)
187 {
188  const struct lpddr4_chan_swizzle_cfg *chan;
189  /* Number of bytes to copy per DQS. */
190  const size_t sz = DQ_BITS_PER_DQS;
191  int rank_mask;
192 
193  /*
194  * Logical channel 0 is comprised of physical channel 0 and 1.
195  * Physical channel 0 is comprised of the CH0_DQB signals.
196  * Physical channel 1 is comprised of the CH0_DQA signals.
197  */
198  cfg->Ch0_DramDensity = rank_density;
199  cfg->Ch1_DramDensity = rank_density;
200  /* Enable ranks on both channels depending on dual rank option. */
201  rank_mask = dual_rank ? 0x3 : 0x1;
202  cfg->Ch0_RankEnable = rank_mask;
203  cfg->Ch1_RankEnable = rank_mask;
204 
205  /*
206  * CH0_DQB byte lanes in the bit swizzle configuration field are
207  * not 1:1. The mapping within the swizzling field is:
208  * indices [0:7] - byte lane 1 (DQS1) DQ[8:15]
209  * indices [8:15] - byte lane 0 (DQS0) DQ[0:7]
210  * indices [16:23] - byte lane 3 (DQS3) DQ[24:31]
211  * indices [24:31] - byte lane 2 (DQS2) DQ[16:23]
212  */
213  chan = &scfg->phys[LP4_PHYS_CH0B];
214  memcpy(&cfg->Ch0_Bit_swizzling[0], &chan->dqs[LP4_DQS1], sz);
215  memcpy(&cfg->Ch0_Bit_swizzling[8], &chan->dqs[LP4_DQS0], sz);
216  memcpy(&cfg->Ch0_Bit_swizzling[16], &chan->dqs[LP4_DQS3], sz);
217  memcpy(&cfg->Ch0_Bit_swizzling[24], &chan->dqs[LP4_DQS2], sz);
218 
219  /*
220  * CH0_DQA byte lanes in the bit swizzle configuration field are 1:1.
221  */
222  chan = &scfg->phys[LP4_PHYS_CH0A];
223  memcpy(&cfg->Ch1_Bit_swizzling[0], &chan->dqs[LP4_DQS0], sz);
224  memcpy(&cfg->Ch1_Bit_swizzling[8], &chan->dqs[LP4_DQS1], sz);
225  memcpy(&cfg->Ch1_Bit_swizzling[16], &chan->dqs[LP4_DQS2], sz);
226  memcpy(&cfg->Ch1_Bit_swizzling[24], &chan->dqs[LP4_DQS3], sz);
227 }
228 
230  int rank_density, int dual_rank,
231  const struct lpddr4_swizzle_cfg *scfg)
232 {
233  const struct lpddr4_chan_swizzle_cfg *chan;
234  /* Number of bytes to copy per DQS. */
235  const size_t sz = DQ_BITS_PER_DQS;
236  int rank_mask;
237 
238  /*
239  * Logical channel 1 is comprised of physical channel 2 and 3.
240  * Physical channel 2 is comprised of the CH1_DQB signals.
241  * Physical channel 3 is comprised of the CH1_DQA signals.
242  */
243  cfg->Ch2_DramDensity = rank_density;
244  cfg->Ch3_DramDensity = rank_density;
245  /* Enable ranks on both channels depending on dual rank option. */
246  rank_mask = dual_rank ? 0x3 : 0x1;
247  cfg->Ch2_RankEnable = rank_mask;
248  cfg->Ch3_RankEnable = rank_mask;
249 
250  /*
251  * CH1_DQB byte lanes in the bit swizzle configuration field are
252  * not 1:1. The mapping within the swizzling field is:
253  * indices [0:7] - byte lane 1 (DQS1) DQ[8:15]
254  * indices [8:15] - byte lane 0 (DQS0) DQ[0:7]
255  * indices [16:23] - byte lane 3 (DQS3) DQ[24:31]
256  * indices [24:31] - byte lane 2 (DQS2) DQ[16:23]
257  */
258  chan = &scfg->phys[LP4_PHYS_CH1B];
259  memcpy(&cfg->Ch2_Bit_swizzling[0], &chan->dqs[LP4_DQS1], sz);
260  memcpy(&cfg->Ch2_Bit_swizzling[8], &chan->dqs[LP4_DQS0], sz);
261  memcpy(&cfg->Ch2_Bit_swizzling[16], &chan->dqs[LP4_DQS3], sz);
262  memcpy(&cfg->Ch2_Bit_swizzling[24], &chan->dqs[LP4_DQS2], sz);
263 
264  /*
265  * CH1_DQA byte lanes in the bit swizzle configuration field are 1:1.
266  */
267  chan = &scfg->phys[LP4_PHYS_CH1A];
268  memcpy(&cfg->Ch3_Bit_swizzling[0], &chan->dqs[LP4_DQS0], sz);
269  memcpy(&cfg->Ch3_Bit_swizzling[8], &chan->dqs[LP4_DQS1], sz);
270  memcpy(&cfg->Ch3_Bit_swizzling[16], &chan->dqs[LP4_DQS2], sz);
271  memcpy(&cfg->Ch3_Bit_swizzling[24], &chan->dqs[LP4_DQS3], sz);
272 }
273 
274 void meminit_lpddr4_enable_channel(FSP_M_CONFIG *cfg, int logical_chan,
275  int rank_density_gb, int dual_rank,
276  const struct lpddr4_swizzle_cfg *scfg)
277 {
278  int fsp_rank_density;
279 
280  switch (rank_density_gb) {
281  case LP4_4Gb_DENSITY:
282  fsp_rank_density = 0;
283  break;
284  case LP4_6Gb_DENSITY:
285  fsp_rank_density = 1;
286  break;
287  case LP4_8Gb_DENSITY:
288  fsp_rank_density = 2;
289  break;
290  case LP4_12Gb_DENSITY:
291  fsp_rank_density = 3;
292  break;
293  case LP4_16Gb_DENSITY:
294  fsp_rank_density = 4;
295  break;
296  default:
297  printk(BIOS_ERR, "Invalid LPDDR4 density: %d Gb\n", rank_density_gb);
298  return;
299  }
300 
301  switch (logical_chan) {
302  case LP4_LCH0:
303  enable_logical_chan0(cfg, fsp_rank_density, dual_rank, scfg);
304  break;
305  case LP4_LCH1:
306  enable_logical_chan1(cfg, fsp_rank_density, dual_rank, scfg);
307  break;
308  default:
309  printk(BIOS_ERR, "Invalid logical channel: %d\n", logical_chan);
310  return;
311  }
312  accumulate_channel_memory(rank_density_gb, dual_rank);
313 }
314 
316  const struct lpddr4_cfg *lpcfg, size_t sku_id)
317 {
318  const struct lpddr4_sku *sku;
319 
320  if (sku_id >= lpcfg->num_skus) {
321  printk(BIOS_ERR, "Too few LPDDR4 SKUs: 0x%zx/0x%zx\n",
322  sku_id, lpcfg->num_skus);
323  return;
324  }
325 
326  printk(BIOS_INFO, "LPDDR4 SKU id = 0x%zx\n", sku_id);
327 
328  sku = &lpcfg->skus[sku_id];
329 
330  meminit_lpddr4(cfg, sku->speed);
331 
332  if (sku->ch0_rank_density) {
333  printk(BIOS_INFO, "LPDDR4 Ch0 density = %d Gb\n",
334  sku->ch0_rank_density);
336  sku->ch0_rank_density,
337  sku->ch0_dual_rank,
338  lpcfg->swizzle_config);
339  }
340 
341  if (sku->ch1_rank_density) {
342  printk(BIOS_INFO, "LPDDR4 Ch1 density = %d Gb\n",
343  sku->ch1_rank_density);
345  sku->ch1_rank_density,
346  sku->ch1_dual_rank,
347  lpcfg->swizzle_config);
348  }
349 
350  cfg->PeriodicRetrainingDisable = sku->disable_periodic_retraining;
351 }
352 
354 {
355  /* Bump this value when the memory configuration parameters change. */
356  return 1;
357 }
@ LP4_PHYS_CH0B
Definition: meminit.h:19
@ LP4_PHYS_CH0A
Definition: meminit.h:18
@ LP4_PHYS_CH1A
Definition: meminit.h:20
@ LP4_PHYS_CH1B
Definition: meminit.h:21
@ LP4_LCH0
Definition: meminit.h:27
@ LP4_LCH1
Definition: meminit.h:28
@ LP4_DQS3
Definition: meminit.h:40
@ LP4_DQS1
Definition: meminit.h:38
@ LP4_DQS0
Definition: meminit.h:37
@ DQ_BITS_PER_DQS
Definition: meminit.h:42
@ LP4_DQS2
Definition: meminit.h:39
@ ODT_A_B_HIGH_HIGH
Definition: meminit.h:72
@ LP4_SPEED_1600
Definition: meminit.h:47
@ LP4_SPEED_2133
Definition: meminit.h:48
@ LP4_SPEED_2400
Definition: meminit.h:49
@ LP4_16Gb_DENSITY
Definition: meminit.h:58
@ LP4_6Gb_DENSITY
Definition: meminit.h:55
@ LP4_4Gb_DENSITY
Definition: meminit.h:54
@ LP4_8Gb_DENSITY
Definition: meminit.h:56
@ LP4_12Gb_DENSITY
Definition: meminit.h:57
static const struct fsp_speed_profiles apl_profile
Definition: meminit.c:120
static void accumulate_channel_memory(int density, int dual_rank)
Definition: meminit.c:17
static int fsp_memory_profile(int speed)
Definition: meminit.c:160
static const struct fsp_speed_profiles glk_profile
Definition: meminit.c:131
static size_t memory_size_mib
Definition: meminit.c:10
static void set_lpddr4_defaults(FSP_M_CONFIG *cfg)
Definition: meminit.c:41
size_t memory_in_system_in_mib(void)
Definition: meminit.c:12
static void enable_logical_chan1(FSP_M_CONFIG *cfg, int rank_density, int dual_rank, const struct lpddr4_swizzle_cfg *scfg)
Definition: meminit.c:229
uint8_t fsp_memory_soc_version(void)
Definition: meminit.c:353
static void enable_logical_chan0(FSP_M_CONFIG *cfg, int rank_density, int dual_rank, const struct lpddr4_swizzle_cfg *scfg)
Definition: meminit.c:184
static const struct speed_mapping apl_mappings[]
Definition: meminit.c:114
static const struct fsp_speed_profiles * get_fsp_profile(void)
Definition: meminit.c:136
static const struct speed_mapping glk_mappings[]
Definition: meminit.c:125
void meminit_lpddr4_enable_channel(FSP_M_CONFIG *cfg, int logical_chan, int rank_density_gb, int dual_rank, const struct lpddr4_swizzle_cfg *scfg)
Definition: meminit.c:274
void meminit_lpddr4(FSP_M_CONFIG *cfg, int speed)
Definition: meminit.c:174
size_t iohole_in_mib(void)
Definition: meminit.c:36
void meminit_lpddr4_by_sku(FSP_M_CONFIG *cfg, const struct lpddr4_cfg *lpcfg, size_t sku_id)
Definition: meminit.c:315
static int validate_speed(int speed)
Definition: meminit.c:144
void * memcpy(void *dest, const void *src, size_t n)
Definition: memcpy.c:7
uint32_t sku_id(void)
#define ARRAY_SIZE(a)
Definition: helpers.h:12
#define MiB
Definition: helpers.h:76
#define GiB
Definition: helpers.h:77
#define printk(level,...)
Definition: stdlib.h:16
@ CONFIG
Definition: dsi_common.h:201
#define FSP_M_CONFIG
Definition: fsp_upd.h:8
enum project_sku sku
Definition: mainboard.c:51
#define BIOS_INFO
BIOS_INFO - Expected events.
Definition: loglevel.h:113
#define BIOS_ERR
BIOS_ERR - System in incomplete state.
Definition: loglevel.h:72
#define BIOS_WARNING
BIOS_WARNING - Bad configuration.
Definition: loglevel.h:86
unsigned char uint8_t
Definition: stdint.h:8
const struct speed_mapping * mappings
Definition: meminit.c:110
size_t num_mappings
Definition: meminit.c:111
size_t num_skus
Definition: meminit.h:113
const struct lpddr4_sku * skus
Definition: meminit.h:112
const struct lpddr4_swizzle_cfg * swizzle_config
Definition: meminit.h:114
uint8_t dqs[LP4_NUM_BYTE_LANES][DQ_BITS_PER_DQS]
Definition: meminit.h:78
struct lpddr4_chan_swizzle_cfg phys[LP4_NUM_PHYS_CHANNELS]
Definition: meminit.h:82
int fsp_value
Definition: meminit.c:106