mb/system76/cml-u/dt: Make use of chipset devicetree
[coreboot.git] / src / soc / intel / apollolake / meminit.c
bloba66ef13c4e0115cdd711974de7c5ea4411bf0d57
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>
7 #include <fsp/soc_binding.h>
8 #include <string.h>
10 static size_t memory_size_mib;
12 size_t memory_in_system_in_mib(void)
14 return memory_size_mib;
17 static void accumulate_channel_memory(int density, int dual_rank)
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;
24 /* Two DRAMs per channel. */
25 sz *= 2;
27 /* Two ranks per channel. */
28 if (dual_rank)
29 sz *= 2;
31 sz *= GiB / MiB;
33 memory_size_mib += sz;
36 size_t iohole_in_mib(void)
38 return 2 * (GiB / MiB);
41 static void set_lpddr4_defaults(FSP_M_CONFIG *cfg)
43 uint8_t odt_config;
45 /* Enable memory down BGA since it's the only LPDDR4 packaging. */
46 cfg->Package = 1;
47 cfg->MemoryDown = 1;
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;
63 /* Always default to attempt to use saved training data. */
64 cfg->DisableFastBoot = 0;
66 /* LPDDR4 is memory down so no SPD addresses. */
67 cfg->DIMM0SPDAddress = 0;
68 cfg->DIMM1SPDAddress = 0;
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;
77 * Set the device width to x16 which is half a LPDDR4 module as that's
78 * what the reference code expects.
80 cfg->Ch0_DeviceWidth = 0x1;
81 cfg->Ch1_DeviceWidth = 0x1;
82 cfg->Ch2_DeviceWidth = 0x1;
83 cfg->Ch3_DeviceWidth = 0x1;
86 * Enable bank hashing (bit 1) and rank interleaving (bit 0) with
87 * a 1KiB address mapping (bits 5:4).
89 cfg->Ch0_Option = 0x3;
90 cfg->Ch1_Option = 0x3;
91 cfg->Ch2_Option = 0x3;
92 cfg->Ch3_Option = 0x3;
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;
98 cfg->Ch0_OdtConfig = odt_config;
99 cfg->Ch1_OdtConfig = odt_config;
100 cfg->Ch2_OdtConfig = odt_config;
101 cfg->Ch3_OdtConfig = odt_config;
104 struct speed_mapping {
105 int logical;
106 int fsp_value;
109 struct fsp_speed_profiles {
110 const struct speed_mapping *mappings;
111 size_t num_mappings;
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 },
120 static const struct fsp_speed_profiles apl_profile = {
121 .mappings = apl_mappings,
122 .num_mappings = ARRAY_SIZE(apl_mappings),
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 },
131 static const struct fsp_speed_profiles glk_profile = {
132 .mappings = glk_mappings,
133 .num_mappings = ARRAY_SIZE(glk_mappings),
136 static const struct fsp_speed_profiles *get_fsp_profile(void)
138 if (CONFIG(SOC_INTEL_GEMINILAKE))
139 return &glk_profile;
140 else
141 return &apl_profile;
144 static int validate_speed(int speed)
146 const struct fsp_speed_profiles *fsp_profile = get_fsp_profile();
147 size_t i;
149 for (i = 0; i < fsp_profile->num_mappings; i++) {
150 /* Mapping exists. */
151 if (fsp_profile->mappings[i].logical == speed)
152 return speed;
155 printk(BIOS_WARNING, "Invalid LPDDR4 speed: %d\n", speed);
156 /* Default to slowest speed */
157 return LP4_SPEED_1600;
160 static int fsp_memory_profile(int speed)
162 const struct fsp_speed_profiles *fsp_profile = get_fsp_profile();
163 size_t i;
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;
170 /* should never happen. */
171 return -1;
174 void meminit_lpddr4(FSP_M_CONFIG *cfg, int speed)
176 speed = validate_speed(speed);
178 printk(BIOS_INFO, "LP4DDR speed is %dMHz\n", speed);
179 cfg->Profile = fsp_memory_profile(speed);
181 set_lpddr4_defaults(cfg);
184 static void enable_logical_chan0(FSP_M_CONFIG *cfg,
185 int rank_density, int dual_rank,
186 const struct lpddr4_swizzle_cfg *scfg)
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;
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.
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;
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]
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);
220 * CH0_DQA byte lanes in the bit swizzle configuration field are 1:1.
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);
229 static void enable_logical_chan1(FSP_M_CONFIG *cfg,
230 int rank_density, int dual_rank,
231 const struct lpddr4_swizzle_cfg *scfg)
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;
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.
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;
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]
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);
265 * CH1_DQA byte lanes in the bit swizzle configuration field are 1:1.
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);
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)
278 int fsp_rank_density;
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;
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;
312 accumulate_channel_memory(rank_density_gb, dual_rank);
315 void meminit_lpddr4_by_sku(FSP_M_CONFIG *cfg,
316 const struct lpddr4_cfg *lpcfg, size_t sku_id)
318 const struct lpddr4_sku *sku;
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;
326 printk(BIOS_INFO, "LPDDR4 SKU id = 0x%zx\n", sku_id);
328 sku = &lpcfg->skus[sku_id];
330 meminit_lpddr4(cfg, sku->speed);
332 if (sku->ch0_rank_density) {
333 printk(BIOS_INFO, "LPDDR4 Ch0 density = %d Gb\n",
334 sku->ch0_rank_density);
335 meminit_lpddr4_enable_channel(cfg, LP4_LCH0,
336 sku->ch0_rank_density,
337 sku->ch0_dual_rank,
338 lpcfg->swizzle_config);
341 if (sku->ch1_rank_density) {
342 printk(BIOS_INFO, "LPDDR4 Ch1 density = %d Gb\n",
343 sku->ch1_rank_density);
344 meminit_lpddr4_enable_channel(cfg, LP4_LCH1,
345 sku->ch1_rank_density,
346 sku->ch1_dual_rank,
347 lpcfg->swizzle_config);
350 cfg->PeriodicRetrainingDisable = sku->disable_periodic_retraining;
353 uint8_t fsp_memory_soc_version(void)
355 /* Bump this value when the memory configuration parameters change. */
356 return 1;