]>
Commit | Line | Data |
---|---|---|
8ef07571 SG |
1 | /* |
2 | * Copyright (c) 2011 The Chromium OS Authors. | |
3 | * (C) Copyright 2010,2011 | |
4 | * Graeme Russ, <graeme.russ@gmail.com> | |
5 | * | |
6 | * Portions from Coreboot mainboard/google/link/romstage.c | |
7 | * Copyright (C) 2007-2010 coresystems GmbH | |
8 | * Copyright (C) 2011 Google Inc. | |
9 | * | |
10 | * SPDX-License-Identifier: GPL-2.0 | |
11 | */ | |
12 | ||
13 | #include <common.h> | |
65dd74a6 SG |
14 | #include <errno.h> |
15 | #include <fdtdec.h> | |
16 | #include <malloc.h> | |
191c008a SG |
17 | #include <net.h> |
18 | #include <rtc.h> | |
19 | #include <spi.h> | |
20 | #include <spi_flash.h> | |
98655f3a SG |
21 | #include <syscon.h> |
22 | #include <asm/cpu.h> | |
65dd74a6 SG |
23 | #include <asm/processor.h> |
24 | #include <asm/gpio.h> | |
25 | #include <asm/global_data.h> | |
06d336cc | 26 | #include <asm/intel_regs.h> |
f6220f1a | 27 | #include <asm/mrccache.h> |
147ba41d | 28 | #include <asm/mrc_common.h> |
aaafcd6c | 29 | #include <asm/mtrr.h> |
65dd74a6 | 30 | #include <asm/pci.h> |
8b900a41 | 31 | #include <asm/report_platform.h> |
65dd74a6 SG |
32 | #include <asm/arch/me.h> |
33 | #include <asm/arch/pei_data.h> | |
34 | #include <asm/arch/pch.h> | |
35 | #include <asm/post.h> | |
36 | #include <asm/arch/sandybridge.h> | |
37 | ||
38 | DECLARE_GLOBAL_DATA_PTR; | |
39 | ||
191c008a SG |
40 | #define CMOS_OFFSET_MRC_SEED 152 |
41 | #define CMOS_OFFSET_MRC_SEED_S3 156 | |
42 | #define CMOS_OFFSET_MRC_SEED_CHK 160 | |
43 | ||
65dd74a6 SG |
44 | ulong board_get_usable_ram_top(ulong total_size) |
45 | { | |
147ba41d | 46 | return mrc_common_board_get_usable_ram_top(total_size); |
65dd74a6 SG |
47 | } |
48 | ||
76b00aca | 49 | int dram_init_banksize(void) |
65dd74a6 | 50 | { |
147ba41d | 51 | mrc_common_dram_init_banksize(); |
76b00aca SG |
52 | |
53 | return 0; | |
65dd74a6 SG |
54 | } |
55 | ||
191c008a SG |
56 | static int read_seed_from_cmos(struct pei_data *pei_data) |
57 | { | |
58 | u16 c1, c2, checksum, seed_checksum; | |
93f8a311 | 59 | struct udevice *dev; |
53327d3e | 60 | int ret = 0; |
93f8a311 | 61 | |
53327d3e SG |
62 | ret = uclass_get_device(UCLASS_RTC, 0, &dev); |
63 | if (ret) { | |
64 | debug("Cannot find RTC: err=%d\n", ret); | |
93f8a311 BM |
65 | return -ENODEV; |
66 | } | |
191c008a SG |
67 | |
68 | /* | |
69 | * Read scrambler seeds from CMOS RAM. We don't want to store them in | |
70 | * SPI flash since they change on every boot and that would wear down | |
71 | * the flash too much. So we store these in CMOS and the large MRC | |
72 | * data in SPI flash. | |
73 | */ | |
9fbc5ccd SG |
74 | ret = rtc_read32(dev, CMOS_OFFSET_MRC_SEED, &pei_data->scrambler_seed); |
75 | if (!ret) { | |
76 | ret = rtc_read32(dev, CMOS_OFFSET_MRC_SEED_S3, | |
77 | &pei_data->scrambler_seed_s3); | |
78 | } | |
79 | if (ret) { | |
80 | debug("Failed to read from RTC %s\n", dev->name); | |
81 | return ret; | |
82 | } | |
83 | ||
191c008a SG |
84 | debug("Read scrambler seed 0x%08x from CMOS 0x%02x\n", |
85 | pei_data->scrambler_seed, CMOS_OFFSET_MRC_SEED); | |
191c008a SG |
86 | debug("Read S3 scrambler seed 0x%08x from CMOS 0x%02x\n", |
87 | pei_data->scrambler_seed_s3, CMOS_OFFSET_MRC_SEED_S3); | |
88 | ||
89 | /* Compute seed checksum and compare */ | |
90 | c1 = compute_ip_checksum((u8 *)&pei_data->scrambler_seed, | |
91 | sizeof(u32)); | |
92 | c2 = compute_ip_checksum((u8 *)&pei_data->scrambler_seed_s3, | |
93 | sizeof(u32)); | |
94 | checksum = add_ip_checksums(sizeof(u32), c1, c2); | |
95 | ||
93f8a311 BM |
96 | seed_checksum = rtc_read8(dev, CMOS_OFFSET_MRC_SEED_CHK); |
97 | seed_checksum |= rtc_read8(dev, CMOS_OFFSET_MRC_SEED_CHK + 1) << 8; | |
191c008a SG |
98 | |
99 | if (checksum != seed_checksum) { | |
100 | debug("%s: invalid seed checksum\n", __func__); | |
101 | pei_data->scrambler_seed = 0; | |
102 | pei_data->scrambler_seed_s3 = 0; | |
103 | return -EINVAL; | |
104 | } | |
105 | ||
106 | return 0; | |
107 | } | |
108 | ||
109 | static int prepare_mrc_cache(struct pei_data *pei_data) | |
110 | { | |
111 | struct mrc_data_container *mrc_cache; | |
4b9f6a66 | 112 | struct mrc_region entry; |
191c008a SG |
113 | int ret; |
114 | ||
115 | ret = read_seed_from_cmos(pei_data); | |
116 | if (ret) | |
117 | return ret; | |
42913a1c | 118 | ret = mrccache_get_region(NULL, &entry); |
191c008a SG |
119 | if (ret) |
120 | return ret; | |
121 | mrc_cache = mrccache_find_current(&entry); | |
122 | if (!mrc_cache) | |
123 | return -ENOENT; | |
124 | ||
3e45de6e BM |
125 | pei_data->mrc_input = mrc_cache->data; |
126 | pei_data->mrc_input_len = mrc_cache->data_size; | |
191c008a SG |
127 | debug("%s: at %p, size %x checksum %04x\n", __func__, |
128 | pei_data->mrc_input, pei_data->mrc_input_len, | |
129 | mrc_cache->checksum); | |
130 | ||
131 | return 0; | |
132 | } | |
133 | ||
191c008a SG |
134 | static int write_seeds_to_cmos(struct pei_data *pei_data) |
135 | { | |
136 | u16 c1, c2, checksum; | |
93f8a311 | 137 | struct udevice *dev; |
53327d3e | 138 | int ret = 0; |
93f8a311 | 139 | |
53327d3e SG |
140 | ret = uclass_get_device(UCLASS_RTC, 0, &dev); |
141 | if (ret) { | |
142 | debug("Cannot find RTC: err=%d\n", ret); | |
93f8a311 BM |
143 | return -ENODEV; |
144 | } | |
191c008a SG |
145 | |
146 | /* Save the MRC seed values to CMOS */ | |
93f8a311 | 147 | rtc_write32(dev, CMOS_OFFSET_MRC_SEED, pei_data->scrambler_seed); |
191c008a SG |
148 | debug("Save scrambler seed 0x%08x to CMOS 0x%02x\n", |
149 | pei_data->scrambler_seed, CMOS_OFFSET_MRC_SEED); | |
150 | ||
93f8a311 | 151 | rtc_write32(dev, CMOS_OFFSET_MRC_SEED_S3, pei_data->scrambler_seed_s3); |
191c008a SG |
152 | debug("Save s3 scrambler seed 0x%08x to CMOS 0x%02x\n", |
153 | pei_data->scrambler_seed_s3, CMOS_OFFSET_MRC_SEED_S3); | |
154 | ||
155 | /* Save a simple checksum of the seed values */ | |
156 | c1 = compute_ip_checksum((u8 *)&pei_data->scrambler_seed, | |
157 | sizeof(u32)); | |
158 | c2 = compute_ip_checksum((u8 *)&pei_data->scrambler_seed_s3, | |
159 | sizeof(u32)); | |
160 | checksum = add_ip_checksums(sizeof(u32), c1, c2); | |
161 | ||
93f8a311 BM |
162 | rtc_write8(dev, CMOS_OFFSET_MRC_SEED_CHK, checksum & 0xff); |
163 | rtc_write8(dev, CMOS_OFFSET_MRC_SEED_CHK + 1, (checksum >> 8) & 0xff); | |
191c008a SG |
164 | |
165 | return 0; | |
166 | } | |
167 | ||
191c008a SG |
168 | /* Use this hook to save our SDRAM parameters */ |
169 | int misc_init_r(void) | |
170 | { | |
171 | int ret; | |
172 | ||
42913a1c | 173 | ret = mrccache_save(); |
191c008a SG |
174 | if (ret) |
175 | printf("Unable to save MRC data: %d\n", ret); | |
176 | ||
177 | return 0; | |
178 | } | |
179 | ||
147ba41d SG |
180 | static void post_system_agent_init(struct udevice *dev, struct udevice *me_dev, |
181 | struct pei_data *pei_data) | |
65dd74a6 | 182 | { |
65dd74a6 | 183 | uint16_t done; |
65dd74a6 SG |
184 | |
185 | /* | |
186 | * Send ME init done for SandyBridge here. This is done inside the | |
187 | * SystemAgent binary on IvyBridge | |
188 | */ | |
1641bb8c | 189 | dm_pci_read_config16(dev, PCI_DEVICE_ID, &done); |
65dd74a6 SG |
190 | done &= BASE_REV_MASK; |
191 | if (BASE_REV_SNB == done) | |
c02a4242 | 192 | intel_early_me_init_done(dev, me_dev, ME_INIT_STATUS_SUCCESS); |
65dd74a6 | 193 | else |
8b900a41 | 194 | intel_me_status(me_dev); |
65dd74a6 | 195 | |
147ba41d SG |
196 | /* If PCIe init is skipped, set the PEG clock gating */ |
197 | if (!pei_data->pcie_init) | |
198 | setbits_le32(MCHBAR_REG(0x7010), 1); | |
199 | } | |
191c008a | 200 | |
147ba41d SG |
201 | static int recovery_mode_enabled(void) |
202 | { | |
203 | return false; | |
191c008a SG |
204 | } |
205 | ||
147ba41d | 206 | static int copy_spd(struct udevice *dev, struct pei_data *peid) |
65dd74a6 | 207 | { |
147ba41d SG |
208 | const void *data; |
209 | int ret; | |
65dd74a6 | 210 | |
147ba41d | 211 | ret = mrc_locate_spd(dev, sizeof(peid->spd_data[0]), &data); |
8d8f3acd SG |
212 | if (ret) { |
213 | debug("%s: Could not locate SPD (ret=%d)\n", __func__, ret); | |
147ba41d | 214 | return ret; |
8d8f3acd | 215 | } |
65dd74a6 | 216 | |
147ba41d | 217 | memcpy(peid->spd_data[0], data, sizeof(peid->spd_data[0])); |
65dd74a6 SG |
218 | |
219 | return 0; | |
220 | } | |
221 | ||
222 | /** | |
223 | * sdram_find() - Find available memory | |
224 | * | |
225 | * This is a bit complicated since on x86 there are system memory holes all | |
226 | * over the place. We create a list of available memory blocks | |
2588e711 SG |
227 | * |
228 | * @dev: Northbridge device | |
65dd74a6 | 229 | */ |
2588e711 | 230 | static int sdram_find(struct udevice *dev) |
65dd74a6 SG |
231 | { |
232 | struct memory_info *info = &gd->arch.meminfo; | |
233 | uint32_t tseg_base, uma_size, tolud; | |
234 | uint64_t tom, me_base, touud; | |
235 | uint64_t uma_memory_base = 0; | |
236 | uint64_t uma_memory_size; | |
237 | unsigned long long tomk; | |
238 | uint16_t ggc; | |
2588e711 | 239 | u32 val; |
65dd74a6 SG |
240 | |
241 | /* Total Memory 2GB example: | |
242 | * | |
243 | * 00000000 0000MB-1992MB 1992MB RAM (writeback) | |
244 | * 7c800000 1992MB-2000MB 8MB TSEG (SMRR) | |
245 | * 7d000000 2000MB-2002MB 2MB GFX GTT (uncached) | |
246 | * 7d200000 2002MB-2034MB 32MB GFX UMA (uncached) | |
247 | * 7f200000 2034MB TOLUD | |
248 | * 7f800000 2040MB MEBASE | |
249 | * 7f800000 2040MB-2048MB 8MB ME UMA (uncached) | |
250 | * 80000000 2048MB TOM | |
251 | * 100000000 4096MB-4102MB 6MB RAM (writeback) | |
252 | * | |
253 | * Total Memory 4GB example: | |
254 | * | |
255 | * 00000000 0000MB-2768MB 2768MB RAM (writeback) | |
256 | * ad000000 2768MB-2776MB 8MB TSEG (SMRR) | |
257 | * ad800000 2776MB-2778MB 2MB GFX GTT (uncached) | |
258 | * ada00000 2778MB-2810MB 32MB GFX UMA (uncached) | |
259 | * afa00000 2810MB TOLUD | |
260 | * ff800000 4088MB MEBASE | |
261 | * ff800000 4088MB-4096MB 8MB ME UMA (uncached) | |
262 | * 100000000 4096MB TOM | |
263 | * 100000000 4096MB-5374MB 1278MB RAM (writeback) | |
264 | * 14fe00000 5368MB TOUUD | |
265 | */ | |
266 | ||
267 | /* Top of Upper Usable DRAM, including remap */ | |
2588e711 SG |
268 | dm_pci_read_config32(dev, TOUUD + 4, &val); |
269 | touud = (uint64_t)val << 32; | |
270 | dm_pci_read_config32(dev, TOUUD, &val); | |
271 | touud |= val; | |
65dd74a6 SG |
272 | |
273 | /* Top of Lower Usable DRAM */ | |
2588e711 | 274 | dm_pci_read_config32(dev, TOLUD, &tolud); |
65dd74a6 SG |
275 | |
276 | /* Top of Memory - does not account for any UMA */ | |
2588e711 SG |
277 | dm_pci_read_config32(dev, 0xa4, &val); |
278 | tom = (uint64_t)val << 32; | |
279 | dm_pci_read_config32(dev, 0xa0, &val); | |
280 | tom |= val; | |
65dd74a6 SG |
281 | |
282 | debug("TOUUD %llx TOLUD %08x TOM %llx\n", touud, tolud, tom); | |
283 | ||
284 | /* ME UMA needs excluding if total memory <4GB */ | |
2588e711 SG |
285 | dm_pci_read_config32(dev, 0x74, &val); |
286 | me_base = (uint64_t)val << 32; | |
287 | dm_pci_read_config32(dev, 0x70, &val); | |
288 | me_base |= val; | |
65dd74a6 SG |
289 | |
290 | debug("MEBASE %llx\n", me_base); | |
291 | ||
292 | /* TODO: Get rid of all this shifting by 10 bits */ | |
293 | tomk = tolud >> 10; | |
294 | if (me_base == tolud) { | |
295 | /* ME is from MEBASE-TOM */ | |
296 | uma_size = (tom - me_base) >> 10; | |
297 | /* Increment TOLUD to account for ME as RAM */ | |
298 | tolud += uma_size << 10; | |
299 | /* UMA starts at old TOLUD */ | |
300 | uma_memory_base = tomk * 1024ULL; | |
301 | uma_memory_size = uma_size * 1024ULL; | |
302 | debug("ME UMA base %llx size %uM\n", me_base, uma_size >> 10); | |
303 | } | |
304 | ||
305 | /* Graphics memory comes next */ | |
2588e711 | 306 | dm_pci_read_config16(dev, GGC, &ggc); |
65dd74a6 SG |
307 | if (!(ggc & 2)) { |
308 | debug("IGD decoded, subtracting "); | |
309 | ||
310 | /* Graphics memory */ | |
311 | uma_size = ((ggc >> 3) & 0x1f) * 32 * 1024ULL; | |
312 | debug("%uM UMA", uma_size >> 10); | |
313 | tomk -= uma_size; | |
314 | uma_memory_base = tomk * 1024ULL; | |
315 | uma_memory_size += uma_size * 1024ULL; | |
316 | ||
317 | /* GTT Graphics Stolen Memory Size (GGMS) */ | |
318 | uma_size = ((ggc >> 8) & 0x3) * 1024ULL; | |
319 | tomk -= uma_size; | |
320 | uma_memory_base = tomk * 1024ULL; | |
321 | uma_memory_size += uma_size * 1024ULL; | |
322 | debug(" and %uM GTT\n", uma_size >> 10); | |
323 | } | |
324 | ||
325 | /* Calculate TSEG size from its base which must be below GTT */ | |
2588e711 | 326 | dm_pci_read_config32(dev, 0xb8, &tseg_base); |
65dd74a6 SG |
327 | uma_size = (uma_memory_base - tseg_base) >> 10; |
328 | tomk -= uma_size; | |
329 | uma_memory_base = tomk * 1024ULL; | |
330 | uma_memory_size += uma_size * 1024ULL; | |
331 | debug("TSEG base 0x%08x size %uM\n", tseg_base, uma_size >> 10); | |
332 | ||
333 | debug("Available memory below 4GB: %lluM\n", tomk >> 10); | |
334 | ||
335 | /* Report the memory regions */ | |
147ba41d SG |
336 | mrc_add_memory_area(info, 1 << 20, 2 << 28); |
337 | mrc_add_memory_area(info, (2 << 28) + (2 << 20), 4 << 28); | |
338 | mrc_add_memory_area(info, (4 << 28) + (2 << 20), tseg_base); | |
339 | mrc_add_memory_area(info, 1ULL << 32, touud); | |
aaafcd6c SG |
340 | |
341 | /* Add MTRRs for memory */ | |
342 | mtrr_add_request(MTRR_TYPE_WRBACK, 0, 2ULL << 30); | |
343 | mtrr_add_request(MTRR_TYPE_WRBACK, 2ULL << 30, 512 << 20); | |
344 | mtrr_add_request(MTRR_TYPE_WRBACK, 0xaULL << 28, 256 << 20); | |
345 | mtrr_add_request(MTRR_TYPE_UNCACHEABLE, tseg_base, 16 << 20); | |
346 | mtrr_add_request(MTRR_TYPE_UNCACHEABLE, tseg_base + (16 << 20), | |
347 | 32 << 20); | |
348 | ||
65dd74a6 SG |
349 | /* |
350 | * If >= 4GB installed then memory from TOLUD to 4GB | |
351 | * is remapped above TOM, TOUUD will account for both | |
352 | */ | |
353 | if (touud > (1ULL << 32ULL)) { | |
354 | debug("Available memory above 4GB: %lluM\n", | |
355 | (touud >> 20) - 4096); | |
356 | } | |
357 | ||
358 | return 0; | |
359 | } | |
360 | ||
361 | static void rcba_config(void) | |
362 | { | |
363 | /* | |
364 | * GFX INTA -> PIRQA (MSI) | |
365 | * D28IP_P3IP WLAN INTA -> PIRQB | |
366 | * D29IP_E1P EHCI1 INTA -> PIRQD | |
367 | * D26IP_E2P EHCI2 INTA -> PIRQF | |
368 | * D31IP_SIP SATA INTA -> PIRQF (MSI) | |
369 | * D31IP_SMIP SMBUS INTB -> PIRQH | |
370 | * D31IP_TTIP THRT INTC -> PIRQA | |
371 | * D27IP_ZIP HDA INTA -> PIRQA (MSI) | |
372 | * | |
373 | * TRACKPAD -> PIRQE (Edge Triggered) | |
374 | * TOUCHSCREEN -> PIRQG (Edge Triggered) | |
375 | */ | |
376 | ||
377 | /* Device interrupt pin register (board specific) */ | |
378 | writel((INTC << D31IP_TTIP) | (NOINT << D31IP_SIP2) | | |
379 | (INTB << D31IP_SMIP) | (INTA << D31IP_SIP), RCB_REG(D31IP)); | |
380 | writel(NOINT << D30IP_PIP, RCB_REG(D30IP)); | |
381 | writel(INTA << D29IP_E1P, RCB_REG(D29IP)); | |
382 | writel(INTA << D28IP_P3IP, RCB_REG(D28IP)); | |
383 | writel(INTA << D27IP_ZIP, RCB_REG(D27IP)); | |
384 | writel(INTA << D26IP_E2P, RCB_REG(D26IP)); | |
385 | writel(NOINT << D25IP_LIP, RCB_REG(D25IP)); | |
386 | writel(NOINT << D22IP_MEI1IP, RCB_REG(D22IP)); | |
387 | ||
388 | /* Device interrupt route registers */ | |
389 | writel(DIR_ROUTE(PIRQB, PIRQH, PIRQA, PIRQC), RCB_REG(D31IR)); | |
390 | writel(DIR_ROUTE(PIRQD, PIRQE, PIRQF, PIRQG), RCB_REG(D29IR)); | |
391 | writel(DIR_ROUTE(PIRQB, PIRQC, PIRQD, PIRQE), RCB_REG(D28IR)); | |
392 | writel(DIR_ROUTE(PIRQA, PIRQH, PIRQA, PIRQB), RCB_REG(D27IR)); | |
393 | writel(DIR_ROUTE(PIRQF, PIRQE, PIRQG, PIRQH), RCB_REG(D26IR)); | |
394 | writel(DIR_ROUTE(PIRQA, PIRQB, PIRQC, PIRQD), RCB_REG(D25IR)); | |
395 | writel(DIR_ROUTE(PIRQA, PIRQB, PIRQC, PIRQD), RCB_REG(D22IR)); | |
396 | ||
397 | /* Enable IOAPIC (generic) */ | |
398 | writew(0x0100, RCB_REG(OIC)); | |
399 | /* PCH BWG says to read back the IOAPIC enable register */ | |
400 | (void)readw(RCB_REG(OIC)); | |
401 | ||
402 | /* Disable unused devices (board specific) */ | |
403 | setbits_le32(RCB_REG(FD), PCH_DISABLE_ALWAYS); | |
404 | } | |
8ef07571 SG |
405 | |
406 | int dram_init(void) | |
407 | { | |
147ba41d | 408 | struct pei_data _pei_data __aligned(8) = { |
65dd74a6 | 409 | .pei_version = PEI_VERSION, |
06d336cc | 410 | .mchbar = MCH_BASE_ADDRESS, |
65dd74a6 SG |
411 | .dmibar = DEFAULT_DMIBAR, |
412 | .epbar = DEFAULT_EPBAR, | |
2d934e57 | 413 | .pciexbar = CONFIG_PCIE_ECAM_BASE, |
65dd74a6 SG |
414 | .smbusbar = SMBUS_IO_BASE, |
415 | .wdbbar = 0x4000000, | |
416 | .wdbsize = 0x1000, | |
417 | .hpet_address = CONFIG_HPET_ADDRESS, | |
418 | .rcba = DEFAULT_RCBABASE, | |
419 | .pmbase = DEFAULT_PMBASE, | |
420 | .gpiobase = DEFAULT_GPIOBASE, | |
421 | .thermalbase = 0xfed08000, | |
422 | .system_type = 0, /* 0 Mobile, 1 Desktop/Server */ | |
423 | .tseg_size = CONFIG_SMM_TSEG_SIZE, | |
424 | .ts_addresses = { 0x00, 0x00, 0x00, 0x00 }, | |
425 | .ec_present = 1, | |
426 | .ddr3lv_support = 1, | |
427 | /* | |
428 | * 0 = leave channel enabled | |
429 | * 1 = disable dimm 0 on channel | |
430 | * 2 = disable dimm 1 on channel | |
431 | * 3 = disable dimm 0+1 on channel | |
432 | */ | |
433 | .dimm_channel0_disabled = 2, | |
434 | .dimm_channel1_disabled = 2, | |
435 | .max_ddr3_freq = 1600, | |
436 | .usb_port_config = { | |
437 | /* | |
438 | * Empty and onboard Ports 0-7, set to un-used pin | |
439 | * OC3 | |
440 | */ | |
441 | { 0, 3, 0x0000 }, /* P0= Empty */ | |
442 | { 1, 0, 0x0040 }, /* P1= Left USB 1 (OC0) */ | |
443 | { 1, 1, 0x0040 }, /* P2= Left USB 2 (OC1) */ | |
444 | { 1, 3, 0x0040 }, /* P3= SDCARD (no OC) */ | |
445 | { 0, 3, 0x0000 }, /* P4= Empty */ | |
446 | { 1, 3, 0x0040 }, /* P5= WWAN (no OC) */ | |
447 | { 0, 3, 0x0000 }, /* P6= Empty */ | |
448 | { 0, 3, 0x0000 }, /* P7= Empty */ | |
449 | /* | |
450 | * Empty and onboard Ports 8-13, set to un-used pin | |
451 | * OC4 | |
452 | */ | |
453 | { 1, 4, 0x0040 }, /* P8= Camera (no OC) */ | |
454 | { 1, 4, 0x0040 }, /* P9= Bluetooth (no OC) */ | |
455 | { 0, 4, 0x0000 }, /* P10= Empty */ | |
456 | { 0, 4, 0x0000 }, /* P11= Empty */ | |
457 | { 0, 4, 0x0000 }, /* P12= Empty */ | |
458 | { 0, 4, 0x0000 }, /* P13= Empty */ | |
459 | }, | |
460 | }; | |
147ba41d | 461 | struct pei_data *pei_data = &_pei_data; |
c02a4242 | 462 | struct udevice *dev, *me_dev; |
65dd74a6 SG |
463 | int ret; |
464 | ||
9532fe3b SG |
465 | /* We need the pinctrl set up early */ |
466 | ret = syscon_get_by_driver_data(X86_SYSCON_PINCONF, &dev); | |
8d8f3acd SG |
467 | if (ret) { |
468 | debug("%s: Could not get pinconf (ret=%d)\n", __func__, ret); | |
9532fe3b | 469 | return ret; |
8d8f3acd | 470 | } |
9532fe3b | 471 | |
3f603cbb | 472 | ret = uclass_first_device_err(UCLASS_NORTHBRIDGE, &dev); |
8d8f3acd SG |
473 | if (ret) { |
474 | debug("%s: Could not get northbridge (ret=%d)\n", __func__, | |
475 | ret); | |
1641bb8c | 476 | return ret; |
8d8f3acd | 477 | } |
98655f3a | 478 | ret = syscon_get_by_driver_data(X86_SYSCON_ME, &me_dev); |
8d8f3acd SG |
479 | if (ret) { |
480 | debug("%s: Could not get ME (ret=%d)\n", __func__, ret); | |
c02a4242 | 481 | return ret; |
8d8f3acd | 482 | } |
147ba41d | 483 | ret = copy_spd(dev, pei_data); |
8d8f3acd SG |
484 | if (ret) { |
485 | debug("%s: Could not get SPD (ret=%d)\n", __func__, ret); | |
65dd74a6 | 486 | return ret; |
8d8f3acd | 487 | } |
147ba41d SG |
488 | pei_data->boot_mode = gd->arch.pei_boot_mode; |
489 | debug("Boot mode %d\n", gd->arch.pei_boot_mode); | |
490 | debug("mrc_input %p\n", pei_data->mrc_input); | |
65dd74a6 | 491 | |
147ba41d SG |
492 | /* |
493 | * Do not pass MRC data in for recovery mode boot, | |
494 | * Always pass it in for S3 resume. | |
495 | */ | |
496 | if (!recovery_mode_enabled() || | |
497 | pei_data->boot_mode == PEI_BOOT_RESUME) { | |
498 | ret = prepare_mrc_cache(pei_data); | |
499 | if (ret) | |
500 | debug("prepare_mrc_cache failed: %d\n", ret); | |
501 | } | |
65dd74a6 | 502 | |
147ba41d SG |
503 | /* If MRC data is not found we cannot continue S3 resume. */ |
504 | if (pei_data->boot_mode == PEI_BOOT_RESUME && !pei_data->mrc_input) { | |
505 | debug("Giving up in sdram_initialize: No MRC data\n"); | |
506 | reset_cpu(0); | |
507 | } | |
65dd74a6 | 508 | |
147ba41d SG |
509 | /* Pass console handler in pei_data */ |
510 | pei_data->tx_byte = sdram_console_tx_byte; | |
65dd74a6 | 511 | |
147ba41d SG |
512 | /* Wait for ME to be ready */ |
513 | ret = intel_early_me_init(me_dev); | |
8d8f3acd SG |
514 | if (ret) { |
515 | debug("%s: Could not init ME (ret=%d)\n", __func__, ret); | |
65dd74a6 | 516 | return ret; |
8d8f3acd | 517 | } |
147ba41d | 518 | ret = intel_early_me_uma_size(me_dev); |
8d8f3acd SG |
519 | if (ret < 0) { |
520 | debug("%s: Could not get UMA size (ret=%d)\n", __func__, ret); | |
147ba41d | 521 | return ret; |
8d8f3acd | 522 | } |
65dd74a6 | 523 | |
147ba41d | 524 | ret = mrc_common_init(dev, pei_data, false); |
8d8f3acd SG |
525 | if (ret) { |
526 | debug("%s: mrc_common_init() failed (ret=%d)\n", __func__, ret); | |
147ba41d | 527 | return ret; |
8d8f3acd | 528 | } |
147ba41d SG |
529 | |
530 | ret = sdram_find(dev); | |
8d8f3acd SG |
531 | if (ret) { |
532 | debug("%s: sdram_find() failed (ret=%d)\n", __func__, ret); | |
147ba41d | 533 | return ret; |
8d8f3acd | 534 | } |
65dd74a6 | 535 | gd->ram_size = gd->arch.meminfo.total_32bit_memory; |
8ef07571 | 536 | |
147ba41d SG |
537 | debug("MRC output data length %#x at %p\n", pei_data->mrc_output_len, |
538 | pei_data->mrc_output); | |
539 | ||
540 | post_system_agent_init(dev, me_dev, pei_data); | |
541 | report_memory_config(); | |
542 | ||
543 | /* S3 resume: don't save scrambler seed or MRC data */ | |
544 | if (pei_data->boot_mode != PEI_BOOT_RESUME) { | |
545 | /* | |
546 | * This will be copied to SDRAM in reserve_arch(), then written | |
547 | * to SPI flash in mrccache_save() | |
548 | */ | |
549 | gd->arch.mrc_output = (char *)pei_data->mrc_output; | |
550 | gd->arch.mrc_output_len = pei_data->mrc_output_len; | |
551 | ret = write_seeds_to_cmos(pei_data); | |
552 | if (ret) | |
553 | debug("Failed to write seeds to CMOS: %d\n", ret); | |
554 | } | |
555 | ||
556 | writew(0xCAFE, MCHBAR_REG(SSKPD)); | |
557 | if (ret) | |
558 | return ret; | |
559 | ||
560 | rcba_config(); | |
561 | ||
8ef07571 SG |
562 | return 0; |
563 | } |